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/tty
był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ł.