Perché questo "mentre leggi" funziona in un terminale, ma non in uno script di shell?


8

Ho riscontrato questo interessante problema popolando la mia barra WM con il testo informativo, che viene applicato impostando il titolo della finestra principale, ovvero xsetroot -name "clever words"

A tal fine, stampare una fortuna funziona benissimo in un terminale:

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

Eppure lo stesso fallisce quando viene eseguito da uno script di shell:

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

produce:

$ sh afilereader
afilereader: 2: leggi: arg count

Naturalmente questo viene risolto assegnando il nostro risultato di fortuna a una variabile, quindi usando xsetroot con detta variabile. Ma vorrei ancora capire perché questo non funziona in una sceneggiatura.

Mi rendo conto che ogni comando su entrambi i lati della pipeline viene eseguito all'interno della propria subshell, ma non riesco a vedere come le loro variabili localizzate potrebbero influenzare il ciclo while read. Oppure le variabili non rientrano nell'ambito di applicazione anche tra le iterazioni del ciclo?

Cosa mi sto perdendo?

Aggiornamento: l' shho usato è collegato al trattino, che è in procinto di rendere POSIX conforme. Utilizzando il più venerabile bashrisolto questo.


1
Il comportamento di dash qui non manifesta alcuna mancanza di conformità POSIX. POSIX non richiede che readsia invocabile senza una variabile: pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html
dubiousjim

Risposte:


10

Sembra che tu stia eseguendo il primo esempio in bash, e il secondo in qualunque cosa sia indicato da /bin/sh, che è una shell POSIX che richiede un argomento da passare specificando la variabile in cui vuoi inserire l'input. Cambiare lo shebang in #!/bin/bashdovrebbe risolverlo.


Buona osservazione @Chris! Che funzioni. Penso che leggerò un po 'la differenza tra she bash.
inverti il

Anormale davvero! Potrei ricollegarmi /bin/sha bash, ma penso che userei bash direttamente da ora in poi, per evitare ambiguità. Grazie :)
inverti il

Le shell frequentemente interattive differiscono dagli script di shell nel buffering del loro output. La lettura da pipe tra processi può comportare comportamenti di tempistica strani se il comando che genera l'output buffer le sue scritture quando viene eseguito in modo non interattivo.
JesseM,

5

Nella sintassi sh, è necessario

IFS= read -r REPLY

Alcune shell come ksh, bash e zsh consentono readdi essere chiamate senza un nome variabile ma il comportamento differisce tra loro. Vedi ad esempio l'output di

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

differendo su tutto bash, zsh, pdksh e ksh93


Questo ha senso perché la shell che stavo usando non conosceva il nome della variabile, grazie @Stephane.
inverti il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.