なぜ "while read ..." 構造に入力されたときだけ "read" へのパイピングが機能するのか?重複
質問
こんな感じで、プログラムの出力から環境変数への入力を読み取るようにしています。
echo first second | read A B ; echo $A-$B
そして、その結果は
-
AとBの両方は常に空です。私は、bashがパイプされたコマンドをサブシェルで実行し、基本的に1つがパイプされた入力を読むことを防ぐことについて読みました。しかし、次のようになります。
echo first second | while read A B ; do echo $A-$B ; done
うまくいったようで、結果は
first-second
どなたか、このロジックを説明していただけませんか?つまり
while
...
done
と同じシェルで実行されます。
echo
と同じシェルで実行され、サブシェルでは実行されないのですか?
どのように解決するのですか?
に対するループを行う方法 標準入力 に対してループを行い、結果を変数に格納する方法
下の
バッシュ
(および他の
シェル
も同様)、何かを別のコマンドにパイプするときに
|
を使うと、暗黙のうちに
フォーク
を暗黙のうちに作成します。サブシェルは、現在のセッションの環境に影響を与えることはできません。
だから、これ。
TOTAL=0
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 |
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done
echo final total: $TOTAL
は期待した結果を出しません! :
9 - 4 = 5 -> TOTAL= 5
3 - 1 = 2 -> TOTAL= 7
77 - 2 = 75 -> TOTAL= 82
25 - 12 = 13 -> TOTAL= 95
226 - 664 = -438 -> TOTAL= -343
echo final total: $TOTAL
final total: 0
計算される場所 合計 はメインスクリプトで再利用することができませんでした。
フォークの反転
を使うことで バッシュ プロセスの置換 , ここでドキュメント または ここでは文字列 のように、フォークを逆向きにすることができます。
ここでは文字列
read A B <<<"first second"
echo $A
first
echo $B
second
ここからドキュメント
while read A B;do
echo $A-$B
C=$A-$B
done << eodoc
first second
third fourth
eodoc
first-second
third-fourth
ループの外側で
echo : $C
: third-fourth
コマンドはこちら
TOTAL=0
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done < <(
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664
)
9 - 4 = 5 -> TOTAL= 5
3 - 1 = 2 -> TOTAL= 7
77 - 2 = 75 -> TOTAL= 82
25 - 12 = 13 -> TOTAL= 95
226 - 664 = -438 -> TOTAL= -343
# and finally out of loop:
echo $TOTAL
-343
これで
$TOTAL
の中で
メインスクリプト
.
にパイプを通す。 コマンドリスト
しかし、対外的にのみ動作するために 標準入力 に対してのみ動作させる場合は、スクリプトの一種を フォーク :
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 | {
TOTAL=0
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done
echo "Out of the loop total:" $TOTAL
}
与えるだろう。
9 - 4 = 5 -> TOTAL= 5
3 - 1 = 2 -> TOTAL= 7
77 - 2 = 75 -> TOTAL= 82
25 - 12 = 13 -> TOTAL= 95
226 - 664 = -438 -> TOTAL= -343
Out of the loop total: -343
注
$TOTAL
の中で使用することはできません。
メインスクリプト
(最後の右中括弧の後
}
).
使用方法 ラストパイプ バッシュオプション
CharlesDuffyが正しく指摘しているように、この動作を変更するために使用されるbashオプションがあります。しかし、そのためには、まず を無効化する必要があります。 ジョブ制御 :
shopt -s lastpipe # Set *lastpipe* option
set +m # Disabling job control
TOTAL=0
printf "%s %s\n" 9 4 3 1 77 2 25 12 226 664 |
while read A B;do
((TOTAL+=A-B))
printf "%3d - %3d = %4d -> TOTAL= %4d\n" $A $B $[A-B] $TOTAL
done
9 - 4 = 5 -> TOTAL= -338
3 - 1 = 2 -> TOTAL= -336
77 - 2 = 75 -> TOTAL= -261
25 - 12 = 13 -> TOTAL= -248
226 - 664 = -438 -> TOTAL= -686
echo final total: $TOTAL
-343
これは動作しますが、私は(個人的に)これが好きではありません、これは 標準 であり、スクリプトを読みやすくする助けにはならないからです。また、ジョブ制御を無効にすることは、この動作にアクセスするために高価に見えます。
注意。
ジョブ制御
がデフォルトで有効なのは
インタラクティブ
セッションでのみ有効です。そのため
set +m
は通常のスクリプトでは必要ありません。
そのため、忘れてしまった
set +m
をスクリプトで実行すると、コンソールで実行した場合とスクリプトで実行した場合で異なる動作になります。これでは、理解するのもデバッグするのも簡単にはいかないでしょう...。
関連
-
[解決済み] シェルスクリプトからエコーを使わずにパスワードを取得する方法
-
[解決済み] bashのタブ補完はどのように機能するのですか?
-
[解決済み] Bashでコマンド出力を隠す方法
-
[解決済み] Makefileでシェルコマンドを使用する方法
-
[解決済み] Cronジョブおよびランダム時間(指定時間内
-
[解決済み] Bashでディレクトリではなく、ファイルだけをリストアップする方法は?
-
[解決済み] Bashでファイル名を一括変更する
-
[解決済み] 接頭辞・接尾辞を使った名前の変更方法について教えてください。
-
[解決済み] 空のディレクトリの検索
-
[解決済み] Bash: 関数をパラメータとして渡す
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】シェルで出力を変数にリダイレクトする方法は?重複
-
[解決済み】パイプからシェル変数に値を読み込む
-
[解決済み] Makefileでシェルコマンドを使用する方法
-
[解決済み] find "の結果をカウントするのに最適な方法は何ですか?
-
[解決済み] Bashのバックチックに相当するバッチ
-
[解決済み] .bashrcのエイリアスをvimのシェルコマンドで使用できるようにするには?(:!...)
-
[解決済み] Bashでコマンドライン引数を変更するには?
-
[解決済み] 指定された時間/日付まで眠る
-
[解決済み] グレースフル・シャットダウンプロセスのシグナルはどのような順番で送ればよいのですか?
-
[解決済み] 現在のシェル内でコマンドの出力を実行するには?