De ce nu este ' posibil să citiți din `stdin` cu` read` când canalizați un script în bash?

Nu „caut soluții sau soluții pentru această problemă. Sunt bine că nu funcționează așa în bash. Pur și simplu nu înțeleg de ce nu funcționează.

Caut un răspuns aprofundat de ce următorul script nu funcționează. Toate rezultatele anterioare ale căutării pe internet, inclusiv postările de pe unix.stackexchange.com, nu au putut clarifica complet acest lucru. Are ceva de-a face cu citirea read din stdin care nu funcționează deoarece stdin este deja” luat „(?) de cat alimentând bash prin conductă?

Exemplu de script bash test.sh:

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

Metoda 1 apelând scriptul cu bash test.sh:

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

Metoda 2 care rulează scriptul prin canalizare către bash:

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

Deci, scriptul revine imediat la prompt, fără a aștepta introducerea sau chiar a imprima a doua linie.

Comentarii

  • A așteptat și a primit intrarea echo "Hello $NAME", apoi a fost terminată.

Răspuns

Tu a citit din stdin cu read, dar ceea ce ați citit a fost următoarea linie de intrare standard – și anume echo "Hello $NAME". După ce ați citit acea linie, nu a mai existat nicio intrare și, prin urmare, nu au existat alte comenzi de executat, iar scriptul s-a terminat.

Există un singur flux de intrare standard și sunteți re încercând să-l folosiți atât pentru cod, cât și pentru date. Acesta este același lucru cu modul în care o sesiune interactivă bash citește comenzi din tastarea dvs., precum și read răspunsuri, precum și orice alte comenzi pe care le executați doresc să utilizeze intrarea standard.

Puteți vedea acest lucru dacă adăugăm o linie suplimentară la sfârșitul scriptului:

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

Ambele oferă o comandă suplimentară pentru a vedea executarea scriptului și ne arată ce a fost citit în NAME:

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

Puteți vedea că variabila conține textual ceea ce a fost scris în fișierul script – nu s-a întâmplat nicio interpolare, execuție sau extindere a variabilei.


Dacă doriți să read de la terminal, este posibil. cel mai simplu mod în care este posibil să funcționeze este să citiți din ieșirea standard în loc de intrarea standard (!), care este probabil conectată la TTY:

read NAME <&1 

mă va aștepta să scriu ceva și apoi să trec la restul programului. De asemenea, puteți utiliza /dev/tty sau $(tty).

Comentarii

  • probabil read var </dev/tty ar fi mai bine decât să presupunem că stdout este conectat la tty-ul contraceptiv.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *