何かが間違っている可能性がありますが、IFSを次のいずれかに設定すると説得力があるようです。注文する事前完了/完了リストにはまったく影響しません。
外部IFS(while
構成外)は、以下のスクリプトに示されているすべての例で支配的です。
ここで何が起こっているのでしょうか?この場合、IFSが何をしているのか私は間違った考えを持っていますか?配列分割の結果が「予想」列に示されているとおりであると予想しました。
#!/bin/bash
xifs() { echo -n "$(echo -n "$IFS" | xxd -p)"; } # allow for null $IFS
show() { x=($1)
echo -ne " (${#x[@]})\t |"
for ((j=0;j<${#x[@]};j++)); do
echo -n "${x[j]}|"
done
echo -ne "\t"
xifs "$IFS"; echo
}
data="a b c"
echo -e "----- -- -- \t --------\tactual"
echo -e "outside \t IFS \tinside"
echo -e "loop \t Field \tloop"
echo -e "IFS NR NF \t Split \tIFS (actual)"
echo -e "----- -- -- \t --------\t-----"
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while read; do echo -ne '\t 1'; show "$REPLY"; done
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne '\t 2'; show "$REPLY"; done
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne '\t 3'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while read; do echo -ne '\t 4'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne '\t 5'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne '\t 6'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while read; do echo -ne '\t 7'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne '\t 8'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne '\t 9'; show "$REPLY"; done
IFS=b; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne '\t10'; show "$REPLY"; done
IFS=b; xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne '\t11'; show "$REPLY"; done
echo -e "----- -- -- \t --------\t-----"
出力:
----- -- -- -------- actual
outside IFS inside assigned
loop Field loop # inner
IFS NR NF Split IFS # expected IFS
----- -- -- -------- ----- # --------- --------
20090a 1 (3) |a|b|c| 20090a #
20090a 2 (3) |a|b|c| 20090a # |a b c| IFS=
20090a 3 (3) |a|b|c| 20090a # |a | c| IFS=b
20 4 (3) |a|b|c| 20 #
20 5 (3) |a|b|c| 20 # |a b c IFS=
20 6 (3) |a|b|c| 20 # |a | c| IFS=b
7 (1) |a b c| #
8 (1) |a b c| # |a|b|c| IFS=" "
9 (1) |a b c| # |a | c| IFS=b
62 10 (2) |a | c| 62 # |a b c| IFS=
62 11 (2) |a | c| 62 # |a|b|c| IFS=" "
----- -- -- -------- ----- --------- -------
答え1
(説明が長くてすみません)
はい、IFS
inの変数はwhile IFS=" " read; do …
残りのコードには影響しません。
まず、シェルコマンドラインに2つの異なる種類の変数があることを指定します。
- シェル変数(シェル内にのみ存在し、シェルのローカル変数です)
- すべてのプロセスに環境変数が存在します。これは通常保存されるため、
fork()
子exec()
プロセスはそれを継承します。
以下を使用してコマンドを呼び出す場合:
A=foo B=bar command
A
foo
コマンドは、(環境)変数がにB
設定されている環境で実行されますbar
。しかし、このコマンドラインを使用すると、現在のシェル変数A
とB
絶え間ない。
これは以下とは異なります。
A=foo; B=bar; command
A
シェル変数とはここで定義されており、B
コマンドは環境変数A
やB
定義なしで実行されます。A
との値B
はからアクセスできませんcommand
。
ただし、一部のシェル変数が-edの場合、export
その環境変数はそのシェル変数と同期されます。例:
export A
export B
A=foo; B=bar; command
このコードを使用すると、両方シェル変数とシェル環境変数foo
はとに設定されますbar
。環境変数は子プロセスに継承されるため、command
その値にアクセスできます。
元の質問に戻るには、次に進みます。
IFS='a' read
影響を受けるだけですread
。実際、この場合、read
変数の値は重要ではありませんIFS
。IFS
行を分割して複数の変数に保存する必要がある場合にのみ使用してください。たとえば、次のようになります。
echo "a : b : c" | IFS=":" read i j k; \
printf "i is '%s', j is '%s', k is '%s'" "$i" "$j" "$k"
IFS
read
パラメーターを使用して呼び出さないと、使用されません。 (編集する:これは完全に正確ではありません。IFS
入力行の先頭/末尾にある空白文字(スペースやタブなど)は常に無視されます。 )
答え2
簡単に言えば、一度に複数の変数を読み取る必要があります。example1IFS=<something> read ...
で設定が目立つ効果を持つようにします。
read
あなたの例の範囲を見逃しました。持ついいえテストケースループ内でIFSを変更します。各行で2番目のIFSが何をしているのかを正確に指摘します。
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS=b read; do echo ...
^ ^
| |
from here --' `- to here :)
これは、シェルで実行されるすべてのプログラムと同じです。コマンドラインで(再)定義する変数はプログラムの実行に影響します。そしてただ(輸出していないので)。したがって、そのような行でオーバーライドを使用するには、値を割り当てるようにIFS
要求する必要があります。read
複数の変数。次の例を確認してください。
$ data="a b c"
$ echo "$data" | while read A B C; do echo \|$A\|$B\|\|$C\|; done
|a|b||c|
$ echo "$data" | while IFS= read A B C; do echo \|$A\|$B\|\|$C\|; done
|a b c||||
$ echo "$data" | while IFS='a' read A B C; do echo \|$A\|$B\|\|$C\|; done
|| b c|||
$ echo "$data" | while IFS='ab' read A B C; do echo \|$A\|$B\|\|$C\|; done
|| || c|
1今学んだとおりザイルズから、1つのフィールドのみを読み取るとき(スペース)に設定すると、実際に利点がある可能性がありますIFS=''
。つまり、行の先頭で空白が切り取られるのを防ぎます。