Nie szukam obejścia ani rozwiązań dla tego problemu. Nie przeszkadza mi to, że nie działa w ten sposób w bash. Po prostu nie rozumiem, dlaczego to nie działa.
Szukam dogłębnej odpowiedzi, dlaczego poniższy skrypt nie działa. Wszystkie poprzednie wyniki wyszukiwania w internecie, w tym posty z unix.stackexchange.com, nie były w stanie całkowicie tego wyjaśnić. Ma to coś wspólnego z read czytaniem z stdin co nie” nie działa, ponieważ stdin jest już „zajęte” (?) przez cat karmienie bash potokiem?
Przykładowy skrypt basha test.sh:
echo "Please say name:" read NAME echo "Hello $NAME"
Metoda 1 wywołująca skrypt z bash test.sh:
$ bash test.sh Please say name: XYZ Hello XYZ $
Metoda 2 uruchamiająca skrypt przez potok do bash:
$ cat test.sh | bash Please say name: $
Dzięki temu skrypt natychmiast powraca do monitu, bez czekania na wprowadzenie danych ani nawet drukowania drugiego
Komentarze
Odpowiedź
Ty czy odczytano ze standardowego wejścia za pomocą read, ale to, co przeczytałeś, to następny wiersz standardowego wejścia – a mianowicie echo "Hello $NAME". Po przeczytaniu tej linii nie było już danych wejściowych, więc nie było dalszych poleceń do wykonania, a skrypt się skończył.
Jest tylko jeden standardowy strumień wejściowy, a ty próbujesz użyć go zarówno do kodu, jak i do danych. To tak samo, jak w przypadku interaktywnej sesji bash, która odczytuje polecenia z Twojego wpisywania, a także read responses, a także wszelkie inne polecenia, które uruchamiasz, aby używać standardowego wejścia.
Możesz to zobaczyć, jeśli dodamy dodatkową linię na końcu skryptu:
echo "Please say name:" read NAME echo "Hello $NAME" printf "name=%s\n" "$NAME"
Oba zapewnia dodatkowe polecenie, aby zobaczyć, jak skrypt kontynuuje wykonywanie, i pokazuje, co zostało wczytane do NAME:
Please say name: name=echo "Hello $NAME"
Możesz zobaczyć, że zmienna zawiera dosłownie to, co zostało zapisane w pliku skryptu – nie nastąpiła żadna interpolacja, wykonanie ani rozwinięcie zmiennej.
Jeśli chcesz read z terminala, jest to możliwe. Najprostszym sposobem, który prawdopodobnie zadziała, jest odczytanie ze standardowego wyjścia zamiast standardowego wejścia (!), które jest prawdopodobnie połączone z TTY:
read NAME <&1
To będzie czekać, aż coś napiszę, a następnie przejdzie do dalszej części programu. Możesz również użyć /dev/tty lub $(tty).
Komentarze
- prawdopodobnie
read var </dev/ttybyłoby lepsze niż założenie, że standardowe wyjście jest połączone z przeklętym tty.
echo "Hello $NAME"i odebrał je, a następnie zakończył.