私は次のwhileループの組み込み関数に精通していますbash
。read
echo "0 1
1 1
1 2
2 3" |\
while read A B; do
echo $A + $B | bc;
done
make
私はファイルを分割して中間結果を保存することが慎重になったいくつかのプロジェクトを進めてきました。したがって、単一の行を変数に分割することがよくあります。以下の例は正常に動作しますが、
head -n1 somefile | while read A B C D E FOO; do [... use vars here ...]; done
whileループは複数回実行されないため、これは少し愚かなことです。しかし、そうでない場合はwhile
、
head -n1 somefile | read A B C D E FOO; [... use vars here ...]
これを使用するときに読み取った変数は常に空です。read
私は通常、多くの同様の行を処理するためにwhileループを使用するので、この動作を見たことがありません。 whileループなしで組み込みbash
関数をどのように使用できますか?read
それとも、1行を複数の(!)変数として読み取る別の(より良い)方法がありますか?
結論として
答えは、これが範囲指定の問題であることを示しています。声明
cmd0; cmd1; cmd2 | cmd3; cmd4
コマンドとして解釈され、cmd0
同じスコープで実行されますが、コマンドとそれぞれにcmd1
独自のサブシェルが提供されるため、スコープは異なります。元のシェルは、2つのサブシェルの親シェルです。cmd4
cmd2
cmd3
答え1
変数を使う部分が新しい命令集合だからだ。代わりにこれを使用してください:
head somefile | { read A B C D E FOO; echo $A $B $C $D $E $FOO; }
この構文では、後ろにスペースを入れ、前に{
(セミコロン)を付ける必要があります。必ずしも必要ではありません。最初の行だけを読みます。;
}
-n1
read
より良い理解のために、上記と同じことをするのに役立ちます。
read A B C D E FOO < <(head somefile); echo $A $B $C $D $E $FOO
編集する:
次の2つの声明は同じ効果を持つとよく言われます。
head somefile | read A B C D E FOO
read A B C D E FOO < <(head somefile)
まあ、まさにそうではありません。 1つ目head
はからのbash
組み込みパイプですread
。あるプロセスの標準出力は別のプロセスの標準入力に移動されます。
2番目の説明は、リダイレクトとプロセスの交換です。bash
独自に処理されます。 FIFO(パイプという名前<(...)
)を作成し、head
その出力をFIFOに接続してからプロセスに<
リダイレクトします。read
これまでは、これらが同じように見えます。ただし、変数を使用する場合はこれが重要です。まず、実行後の変数は設定されません。第二に、現在の環境で使用できます。
この状況では、各シェルは異なる動作をします。バラよりそのリンク彼らはこれのためにここにあります。コマンドのグループ化、プロセス置換()、またはここで文字列()を使用してbash
この動作を解決できます。{}
< <()
<<<
答え2
非常に便利な記事から引用wiki.bash-hackers.org:
これは、パイプされたコマンドが親シェルを変更できないサブシェルで実行されるためです。したがって、親シェルの変数は変更されません(文書参照:Bashとプロセスツリー)。
回答が複数回提供されたので、他の方法(組み込みのコマンドを使用して...)は次のようになります。
$ eval `echo 0 1 | awk '{print "A="$1";B="$2}'`;echo $B $A
$ 1 0
答え3
指摘したように、問題はパイプがread
サブシェルで実行されることです。
1つの答えは、次を使用することです。トレドック:
numbers="01 02"
read first second <<INPUT
$numbers
INPUT
echo $first
echo $second
このアプローチは、POSIX と同様のシェルで同じように動作するため、良いです。