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
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.
Há 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.
echo "Hello $NAME"
e foi encerrado.