Por que esse "enquanto lido" funciona em um terminal, mas não em um shell script?

8

Eu me deparei com esse problema interessante enquanto preenchia minha barra WM com texto informativo, que é aplicado definindo o título da janela raiz, ou seja, xsetroot -name "clever words"

Para esse fim, imprimir uma fortuna funciona bem em um terminal:

fortune -s | while read -r; do xsetroot -name "$REPLY"; done

No entanto, o mesmo falha quando executado a partir de um script de shell:

#!/bin/sh
cat /tmp/afile | while read; do echo "$REPLY"; done

Produz:

$ sh afilereader
afilereader: 2: leia: arg count

É claro que isso é remediado atribuindo nosso resultado da sorte a uma variável e depois usando xsetroot com a referida variável. Mas eu ainda gostaria de entender por que isso não funciona em um script.

Percebo que cada comando em ambos os lados do pipeline é executado dentro de seu próprio subshell, mas não consigo ver como suas variáveis ​​localizadas podem afetar o loop while read. Ou as variáveis ​​estão fora do escopo mesmo entre as iterações do loop?

o que estou perdendo?

Atualização: O que sheu usei está vinculado ao traço, que está no processo de tornar-se compatível com POSIX. Usando o mais venerável bashresolveu isso.

invertido
fonte
1
O comportamento do hífen aqui não manifesta falta de conformidade com o POSIX. POSIX não exigem que o readser invocable sem uma variável: pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html
dubiousjim

Respostas:

10

Você parece estar executando o primeiro exemplo em bash, e o segundo no que quer que seja apontado por /bin/sh, que é um shell POSIX que requer que um argumento seja passado especificando a variável na qual você deseja inserir a entrada. Alterar o shebang para #!/bin/bashdeve corrigir isso.

Chris Down
fonte
Boa observação @ Chris! Isso funciona. Acho que vou ler um pouco sobre a diferença entre she bash.
Invert
Anormal mesmo! Eu poderia vincular novamente /bin/shao bash, mas acho que eu usaria o bash diretamente a partir de agora, para evitar ambiguidade. Obrigado :)
inverter
Os shells interativos frequentemente diferem dos scripts de shell no buffer de sua saída. A leitura de pipes entre processos pode resultar em todos os tipos de comportamentos de tempo estranhos, se o comando que gera saída armazena em buffer suas gravações quando executado de maneira não interativa.
JesseM
5

Na sintaxe sh, você precisa

IFS= read -r REPLY

Alguns shells como ksh, bash e zsh permitem readser chamados sem um nome de variável, mas o comportamento difere entre eles. Veja, por exemplo, a saída de

printf 'te\ st\\\na ' | "$shell" -c 'read; printf "%s\n" "<$REPLY>"'

diferindo em todos os bash, zsh, pdksh e ksh93

Stéphane Chazelas
fonte
Isso faz sentido porque o shell que eu estava usando não sabia o nome da variável, obrigado @Stephane.
Invert