web-dev-qa-db-ja.com

スクリプトをbashにパイプするときに、 `read`を使用して` stdin`から読み取ることができないのはなぜですか?

この問題の回避策や解決策は探していません。 bashでは、そのように機能しないので問題ありません。わからないなぜ動かない.

次のスクリプトが機能しない理由の詳細な答えを探しています。 unix.stackexchange.comからの投稿を含め、以前のすべてのインターネット検索結果では、これを完全にクリアすることはできませんでした。 readは、stdinがパイプを介してstdinをフィードすることによって既に「取得」されているため(?)、catからのbashの読み取りと関係があります。

Bashスクリプトの例test.sh

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

方法1は、bash test.shを使用してスクリプトを呼び出します。

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

方法2は、bashへのパイプを介してスクリプトを実行します。

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

そのため、スクリプトは入力を待つことなく、または2行目を印刷することもなく、すぐにプロンプ​​トに戻ります。

2
finefoot

あなたdidreadを使用してstdinから読み取りましたが、読み取ったのは標準入力の次の行、つまり_echo "Hello $NAME"_でした。その行を読んだ後、入力がなくなったため、実行するコマンドがなくなり、スクリプトは終了しました。

標準入力ストリームは1つだけあり、それをコードとデータの両方に使用しようとしています。これは、対話型のbashセッションが入力からコマンドを読み取り、read応答だけでなく、実行する他のコマンドが標準入力を使用する場合と同じです。

スクリプトの最後に行を追加すると、これが発生していることがわかります。

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

これは、スクリプトが実行を継続するのを確認するための追加のコマンドを提供し、NAMEに読み込まれた内容を示します。

_Please say name:
name=echo "Hello $NAME"
_

変数がスクリプトファイルに書き込まれた内容を保持しているverbatimことがわかります。変数の補間、実行、拡張は行われていません。


端末からreadを使用したい場合は、それが可能です。動作する可能性が最も高い方法は、おそらくTTYに接続されている標準入力(!)ではなく標準出力から読み取ることです。

_read NAME <&1
_

これは私が何かをタイプするのを待ってから、プログラムの残りの部分に移ります。 _/dev/tty_または$(tty)を使用することもできます。

3
Michael Homer