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
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.
echo "Hello $NAME"
och avslutades sedan.