Dlaczego nie ' nie można czytać ze `stdin` za pomocą` read` podczas przesyłania skryptu do bash?

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

  • Czekał na wejście echo "Hello $NAME" i odebrał je, a następnie zakończył.

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.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *