Waarom is het niet mogelijk om ' te lezen van `stdin` met` read` bij het pipen van een script naar bash?

Ik “ben niet op zoek naar tijdelijke oplossingen of oplossingen voor het probleem. Ik” vind het prima dat het niet zo werkt in bash. Ik begrijp gewoon niet waarom het niet “werkt.

Ik ben op zoek naar een diepgaand antwoord waarom het volgende script niet werkt. Alle eerdere zoekresultaten op internet, inclusief berichten van unix.stackexchange.com, konden dit niet helemaal duidelijk maken. Het heeft iets te maken met het lezen van read van stdin wat niet” werkt omdat stdin al “bezet” (?) is door cat die bash via de pipe?

Voorbeeld bash-script test.sh:

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

Methode 1 die het script aanroept met bash test.sh:

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

Methode 2 het script uitvoeren via piping naar bash:

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

Dus het script keert onmiddellijk terug naar de prompt, zonder te wachten op invoer of zelfs de tweede af te drukken regel.

Reacties

  • Het wachtte op en ontving invoer echo "Hello $NAME", en werd vervolgens beëindigd.

Antwoord

Jij heeft gelezen van stdin met read, maar wat je las was de volgende regel met standaardinvoer – namelijk echo "Hello $NAME". Na het lezen van die regel was er geen invoer meer en dus geen verdere opdrachten om uit te voeren, en het script was voorbij.

Er is slechts één standaard invoerstroom, en je bent proberen het te gebruiken voor zowel code als gegevens. Dit is hetzelfde als hoe een interactieve bash -sessie commandos leest van je typewerk, evenals read reacties, evenals alle andere commandos die je uitvoert en waarvoor je standaardinvoer wilt gebruiken.

Je kunt dit zien gebeuren als we een extra regel aan het einde van het script toevoegen:

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

Dit biedt beide een verder commando om te zien dat het script verder wordt uitgevoerd, en laat ons zien wat er is ingelezen in NAME:

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

Je kunt zien dat de variabele woordelijk bevat wat in het scriptbestand is geschreven – er is geen interpolatie, uitvoering of uitbreiding van variabelen gebeurd.


Als u read vanaf de terminal wilt, is dat mogelijk. De eenvoudigste manier die “waarschijnlijk werkt, is lezen van standaarduitvoer in plaats van standaardinvoer (!), die vermoedelijk is verbonden met de TTY:

read NAME <&1 

Dit wacht tot ik iets typ en ga dan verder met de rest van het programma. Je kunt ook /dev/tty of $(tty) gebruiken.

Reacties

  • aantoonbaar read var </dev/tty zou beter zijn dan aan te nemen dat stdout is verbonden met de contrilling tty.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *