web-dev-qa-db-fra.com

Pourquoi n'est-il pas possible de lire de `stdin` avec` Lire` lorsque vous pouvez passer un script à bash?

Je ne cherche pas de travail ou de solutions pour la question. Je vais bien avec ça ne fonctionne pas comme ça dans bash. Je ne comprends tout simplement pas pourquoi ça ne marche pas.

Je cherche une réponse en profondeur pour laquelle le script suivant ne fonctionne pas. Tous les résultats de la recherche Internet précédents, y compris les messages de Unix.stackexchange.com, ne pouvaient pas vraiment clarifier complètement cela. Il a quelque chose à voir avec read lecture de stdin qui ne fonctionne pas parce que stdin est déjà "pris" (?) Par cat Nourrir bash via le tuyau?

Exemple de script Bash test.sh:

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

Méthode 1 appelant le script avec bash test.sh:

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

Méthode 2 exécutant le script via la tuyauterie à bash:

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

Donc, le script revient immédiatement à l'invite, sans attendre l'entrée ni même l'impression de la deuxième ligne.

3
finefoot

Vous DID Lire de stdin avec read, mais ce que vous avez lu était la prochaine ligne d'entrée standard - à savoir echo "Hello $NAME". Après avoir lu cette ligne, il n'y avait plus d'entrées et donc aucune autre commande d'exécution et que le script était terminé.

Il y a un seul flux d'entrée standard et que vous essayez de l'utiliser pour le code et les données. C'est la même chose que la façon dont une session interactive bash session lit les commandes de votre dactylographie, ainsi que des réponses read, ainsi que quelles que soient toutes les autres commandes que vous exécutez souhaitant utiliser une entrée standard.

Vous pouvez voir cela se produire si nous ajoutons une ligne supplémentaire à la fin du script:

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

Cela fournit une commande supplémentaire pour voir le script poursuivre l'exécution et nous montre ce qui a été lu dans NAME:

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

Vous pouvez voir que la variable contient Verbatim Qu'est-ce qui a été écrit dans le fichier de script - aucune interpolation variable, exécution ou expansion n'est arrivée.


Si vous voulez read du terminal, il est possible. La manière la plus simple de travailler est de lire à partir de la sortie standard au lieu de l'entrée standard (!), Qui est vraisemblablement connectée au TTY:

read NAME <&1

Cela m'attendra à de taper quelque chose, puis passez au reste du programme. Vous pouvez également utiliser /dev/tty Ou $(tty).

5
Michael Homer