bash scripting - lê tarball de stdin

7

Eu tenho uma tarefa que preciso escrever em um script que, na minha opinião, deve ser estupidamente simples, mas na verdade estou tendo um tempo bastante difícil.

Eu tenho um script curto que pega um tipo específico de aplicativo no formato tarball e o cria. Atualmente, são necessários apenas dois argumentos de linha de comando: o nome do aplicativo e a localização do tarball. Mas estou me preparando para implantar o script de construção em um sistema de vários hosts e, em vez disso, gostaria que esse script tomasse o tarball do aplicativo em stdin, que seria canalizado por ssh. Por exemplo, aqui está como eu gostaria de chamar o script:

ssh build-host "/usr/local/bin/build-app.sh myapp" < /tmp/myapp.tar.gz

Quando chamado dessa forma, o script de construção tentará criar um aplicativo chamado "myapp".

Eu quero que o script de construção realize algumas verificações de integridade antes de ler o tarball. Além disso, deve sair normalmente se os testes de sanidade falharem. Então, aqui está a essência da minha primeira tentativa no script de construção:

#!/bin/bash

appname=$1

# example sanity check
if [ ! -d "/apps/$appname" ]; then
    mkdir "/apps/$appname"
else
    echo "Error! The app already has been built."
    exit 1
fi

# more sanity checks...

# if passed all tests, then read stdin into tarfile
cat > "/apps/$appname/app.tar.gz"

# build app ...

Isso quase funciona. O problema é que eu não consigo descobrir como ler de stdin no meio de um script bash. O truque cat > file só funciona se eu colocá-lo na primeira linha do script. Mas eu não quero fazer isso. Na primeira linha do script, nenhuma das verificações de sanidade foi executada e não há como determinar onde colocar o tarfile. Eu poderia ter várias instâncias do script sendo executadas de uma vez e não haveria uma boa maneira de evitar colisões.

(Além de cat > file , eu também tentei truques como < /dev/stdin > file com resultados muito semelhantes.)

Então eu também tentei o seguinte:

#!/bin/bash

tarball="$(cat)"
appname="$1"

# example sanity check
if [ ! -d "/apps/$appname" ]; then
    mkdir "/apps/$appname"
else
    echo "Error! The app already has been built."
    exit 1
fi

# more sanity checks...

# if passed all tests, then read stdin into tarfile
echo -n "$tarball" > "/apps/$appname/app.tar.gz"

# build app ...

Mas isso também foi bastante problemático, por dois motivos. Primeiro, não funcionou. echo , mesmo com o -n flag, não parece ser projetado para dados binários e o arquivo tar resultante foi corrompido. Em segundo lugar, isso requer o armazenamento do tarball inteiro como uma variável como o primeiro passo. Isso não só foi mais lento do que o desejado, mesmo para o tarball de teste de 5 MB, mas também pode significar alto consumo de memória, especialmente para os aplicativos maiores com os quais provavelmente lidarei.

Eu gosto da idéia de ler o tarfile do stdin. Isso significaria que o script bash pode simplesmente fechar o pipe se achar que precisa ser anulado, e pode permitir que o script bash decida onde colocar todos os tarballs do aplicativo, ao contrário da versão original de invocar o script de construção, que ficou assim:

scp /tmp/myapp.tar.gz build-host:/tmp/
ssh build-host /usr/local/bin/build-app.sh myapp /tmp/myapp.tar.gz

Este método de invocação é problemático por (esperançosamente) razões óbvias.

Eu realmente estou esperando que eu possa fazer este script funcionar funcionar lendo stdin ou alguma outra forma de pipe ou buffer. Há alguma idéia de como fazer isso funcionar?

    
por jayhendren 10.03.2014 / 20:17

1 resposta

6

O cat > file deve funcionar, não importa quando você o chama, contanto que você não tenha lido antes e "use" o fluxo de entrada, ou feche o descritor de arquivo, o que você não faz. Este é um comando completamente legal e normal e funciona, pelo menos do meu lado.

    
por 10.03.2014 / 20:31