Varför är det inte ' det är möjligt att läsa från `stdin` med` read när man skickar ett manus till bash?

Jag letar inte efter lösningar eller lösningar för problemet. Jag mår bra med att det inte fungerar så i bash. Jag förstår bara inte varför det fungerar inte.

Jag letar efter ett fördjupat svar varför följande skript inte fungerar. Alla tidigare internetsökresultat, inklusive inlägg från unix.stackexchange.com, kunde inte rensa detta helt. Det har något att göra med att read läser från stdin vilket inte fungerar eftersom stdin redan” tas ”(?) av cat matning bash via röret?

Exempel bash-skript test.sh:

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

Metod 1 som kallar skriptet med bash test.sh:

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

Metod 2 som kör skriptet via piping till bash:

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

Så skriptet återgår omedelbart till uppmaningen utan att vänta på inmatning eller ens skriva ut den andra rad.

Kommentarer

  • Den väntade på och fick input echo "Hello $NAME" och avslutades sedan.

Svar

Du läste från stdin med read, men det du läste var nästa rad med standardinmatning – nämligen echo "Hello $NAME". Efter att ha läst den raden fanns det inte mer inmatning och så inga ytterligare kommandon att utföra, och skriptet var över.

Det finns bara en standardinmatningsström, och du är försöker använda den för både kod och data. Detta är samma som hur en interaktiv bash -session läser kommandon från din typ samt read svar, liksom alla andra kommandon du kör vill använda standardinmatning för.

Du kan se detta hända om vi lägger till en extra rad i slutet av skriptet:

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

Detta ger både ett ytterligare kommando för att se skriptet fortsätta körningen och visar oss vad som lästes in i NAME:

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

Du kan se att variabeln innehåller verbatim vad som skrevs i skriptfilen – ingen variabel interpolering, exekvering eller expansion har hänt.


Om du vill read från terminalen är det möjligt. enklaste sättet som troligtvis fungerar är att läsa från standardutdata istället för standardingång (!), som antagligen är ansluten till TTY:

read NAME <&1 

Detta väntar på att jag skriver något och fortsätter sedan till resten av programmet. Du kan också använda /dev/tty eller $(tty).

Kommentarer

  • utan tvekan read var </dev/tty skulle vara bättre än att anta att stdout är kopplat till den sammansatta ttyen.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *