Por que ' não é possível ler de `stdin` com` read` ao enviar um script para o bash?

Não estou procurando soluções alternativas ou soluções para o problema. Não há problema em não funcionar assim em bash. Simplesmente não entendo por que isso não funciona.

Estou procurando uma resposta detalhada por que o script a seguir não funciona. Todos os resultados de pesquisas anteriores na Internet, incluindo postagens de unix.stackexchange.com, não puderam “esclarecer isso completamente. Tem algo a ver com read lendo stdin que não funciona porque stdin já foi” levado “(?) por cat alimentação bash pelo pipe?

Exemplo de script bash test.sh:

echo "Please say name:" read NAME echo "Hello $NAME" 

Método 1 chamando o script com bash test.sh:

$ bash test.sh Please say name: XYZ Hello XYZ $ 

Método 2 executando o script via piping para bash:

$ cat test.sh | bash Please say name: $ 

Assim, o script retorna imediatamente ao prompt, sem esperar pela entrada ou mesmo imprimir o segundo linha.

Comentários

  • Ele esperou e recebeu entrada echo "Hello $NAME" e foi encerrado.

Resposta

Você leu de stdin com read, mas o que você leu foi a próxima linha de entrada padrão – a saber echo "Hello $NAME". Depois de ler essa linha, não havia mais entrada e, portanto, não havia mais comandos para executar e o script acabou.

apenas um fluxo de entrada padrão, e você está tentando usá-lo para código e dados. É o mesmo que uma sessão bash interativa lê comandos de sua digitação, bem como read answers, bem como quaisquer outros comandos para os quais você execute deseja usar a entrada padrão.

Você pode ver isso acontecendo se adicionarmos uma linha extra ao final do script:

echo "Please say name:" read NAME echo "Hello $NAME" printf "name=%s\n" "$NAME" 

Isso fornece um comando adicional para ver o script continuar a execução e nos mostra o que foi lido em NAME:

Please say name: name=echo "Hello $NAME" 

Você pode ver que a variável contém literalmente o que foi escrito no arquivo de script – nenhuma interpolação, execução ou expansão de variável aconteceu.


Se você deseja read a partir do terminal, é possível. a maneira mais simples que provavelmente funcionará é ler a saída padrão em vez da entrada padrão (!), que está presumivelmente conectada ao TTY:

read NAME <&1 

Este irá esperar que eu digite algo e, em seguida, prossiga para o resto do programa. Você também pode usar /dev/tty ou $(tty).

Comentários

  • sem dúvida read var </dev/tty seria melhor do que assumir que o stdout está conectado ao tty de controle.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *