次のシェルスクリプトを考えてみましょう。
echo foo; read; echo bar
出力「foo」を実行し、bash my_script
戻りキーを待ってから「bar」を出力します。
この方法で実行すると正常に動作しますが、/bin/bash にパイプすると動作しなくなります。
$ echo 'echo foo;read;echo bar'|bash
キーを押すのを待たずに「foo」と「bar」を直接出力します。
このように使用すると、なぜもう機能しませんか?
ファイルスクリプトファイルと/ bin / bashにパイプされたスクリプト文字列形式でスクリプトを再構築する方法はありますか?
答え1
実際にはとても簡単です。まず、記憶された記述子に標準入力を維持する必要があります。
exec 9<&0
そこに。コピーを作成しました。それでは、シェルからコマンドをパイプしてみましょう。
echo 'echo foo; read <&9; echo bar' | bash
...まあ、それは簡単です。もちろん、まだ終わっていません。私たちはそれをきれいにする必要があります。
exec 9<&-
さて、もう終わりました。
ただし、コマンドを少しだけグループ化すると、クリーンアップ操作を回避できます。
{ echo 'echo foo; read <&9; echo bar' | bash; } 9<&0
この場合、記述子は、割り当てられた複合コマンドが有効な場合にのみ有効です。
答え2
bash組み込みコマンドはread
標準入力(fd0)からデータを読み取りますが、bashコマンド自体が標準入力を使用するため、標準入力を開くことはできません。
eval
何を制御できますか?
eval 'echo foo;read;echo bar'
例:標準入力から読み取る必要があるシェルスクリプトをパイプする他の方法は考えられません。シェルにパイプすると、シェルはインタラクティブではありません。
私は標準入力ファイル記述子をコピーする方法をまったく知りませんでした。これについてのMikeの答えを参照してください。
ところで:読むと何が起こるのか分かります。
echo 'echo foo;read;echo bar'|strace bash
答え3
ikrabbeの答えは、コマンドラインが期待どおりに機能しない理由を正確に指摘しています。コマンドラインに対して新しいシェルを呼び出す一般的な方法は次のとおりです。
$ sh -c 'echo foo; read; echo bar'
もちろんbash
、必要に応じてこれを使用できますが、1行のシェルスクリプトで実行したい操作の98%は通常のシェルで実行できます。 (「平らな古いシェル」は「POS」の略です。)
あなたの目標が1行のシェルスクリプトを一時停止し、ユーザー入力(おそらく単に確認/確認)を待つことであれば、おそらくこれを行う必要があります。目標がシェルのしくみをよりよく理解することである場合は、次のことを試してください。
$(echo 'echo foo; 読み; echo "$REPLY bar"'; エコキャンディ) $(echo 'echo foo; 読み; echo "$REPLY bar"'; エコキャンディ) | シェン 金持ち キャンディーバー (待つ必要はありません) $