Q1。フィールド分割。
フィールド分割は単語分割と同じですか?
はい、両方とも同じ考えを示しています。
設定IFS=''
はnullと同じですか、空の文字列とも同じですか?
はい、3つとも同じ意味です。フィールド/単語の分割は実行されません。また、これはフィールドの印刷に影響します(と同様echo "$*"
)。すべてのフィールドはスペースなしで連結されます。
Q3:(パートa)IFSの設定を解除します。
POSIX仕様では、次を読みました。
IFSが設定されていない場合、シェルはIFSの値が<space> <tab> <newline>であるかのように動作します。
これは次のものとまったく同じです。
を使用するunset IFS
と、シェルはIFSがデフォルトのように動作します。
つまり、「フィールド分割」はデフォルトのIFS値とまったく同じになるか、設定されません。
これは、IFSがすべての条件で同じように機能するという意味ではありません。、より具体的なものを実行すると、OldIFS=$IFS
VARを設定しますOldIFS
にはnull、デフォルトではありません。このように、IFSを元に戻すと、IFS=OldIFS
IFSはnullに設定され、以前のように未設定のままになりません。気を付けて !!。
Q3:(パートb)IFSを復元します。
IFSの値をデフォルトに戻すにはどうすればよいですか。IFSのデフォルト値を復元するとします。それ、どうやったら出来るの?(より具体的には、どのように<tab>と<newline>を参照しますか?)
zsh、ksh、およびbash(AFAIK)の場合、IFSは次のようにデフォルト値に設定できます。
IFS=$' \t\n' # works with zsh, ksh, bash.
完了、他に何も読む必要はありません。
ただし、shのIFSを再設定する必要がある場合、複雑になる可能性があります。
欠点のない(複雑さを除く)簡単に完了できるものを見てみましょう。
1.- IFSの設定を解除します。
できましたunset IFS
(上記のQ3パートaをお読みください)。
2.-文字を交換します。
回避策として、tabとnewlineの値を交換すると、IFSの値を簡単に設定でき、同等の方法で機能します。
IFSを<space> <newline> <tab>に設定します。
sh -c 'IFS=$(echo " \n\t"); printf "%s" "$IFS"|xxd' # Works.
3.-簡単ですか?解決:
IFSを正しく設定する必要がある子スクリプトがある場合、いつでも手動で記述できます。
IFS = '
'
手動で入力したシーケンスは次のIFS=
'spacetabnewline'とおりです。実際に上記で正しく入力されたシーケンス(確認する必要がある場合は、この回答を編集してください)。ただし、ブラウザが空白を圧縮/非表示にするため、ブラウザからのコピー/貼り付けは失敗します。上記のコードを共有することは難しくなります。
4.-完全なソリューション。
安全にコピーできるコードを作成するには、通常、明確な印刷可能なエスケープが必要です。
期待値を「生成」するコードが必要です。しかし、概念的に正しい場合でも、このコードは末尾を設定しません\n
:
sh -c 'IFS=$(echo " \t\n"); printf "%s" "$IFS"|xxd' # wrong.
これは、ほとんどのシェルでは、展開時にすべての末尾の改行$(...)
または`...`
コマンド置換が削除されるために発生します。
shにトリックを使用する必要があります。
sh -c 'IFS="$(printf " \t\nx")"; IFS="${IFS%x}"; printf "$IFS"|xxd' # Correct.
別の方法として、IFSを(たとえば)bashから環境値として設定してから、sh(環境を介して設定されるIFSを受け入れるバージョン)を呼び出すこともできます。
env IFS=$' \t\n' sh -c 'printf "%s" "$IFS"|xxd'
要するに、shはIFSをデフォルトにリセットすることを非常に奇妙な冒険にします。
Q4:実際のコードでは:
最後に、このコードはどのようになりますか:
while IFS= read -r line
do
echo $line
done < /path_to_text_file
最初の行を次のように変更すると動作します
while read -r line # Use the default IFS value
または:
while IFS=' ' read -r line
最初に:echo $line
(var not quoted)がポルポースにあるかどうかはわかりません。読み取りにはない第2レベルの「フィールド分割」が導入されています。だから私は両方に答えます。:)
このコードで(確認できるように)。便利なxxdが必要です:
#!/bin/ksh
# Correctly set IFS as described above.
defIFS="$(printf " \t\nx")"; defIFS="${defIFS%x}";
IFS="$defIFS"
printf "IFS value: "
printf "%s" "$IFS"| xxd -p
a=' bar baz quz '; l="${#a}"
printf "var value : %${l}s-" "$a" ; printf "%s\n" "$a" | xxd -p
printf "%s\n" "$a" | while IFS='x' read -r line; do
printf "IFS --x-- : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
printf 'Values quoted :\n' "" # With values quoted:
printf "%s\n" "$a" | while IFS='' read -r line; do
printf "IFS null quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
printf "%s\n" "$a" | while IFS="$defIFS" read -r line; do
printf "IFS default quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
unset IFS; printf "%s\n" "$a" | while read -r line; do
printf "IFS unset quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
IFS="$defIFS" # set IFS back to default.
printf "%s\n" "$a" | while IFS=' ' read -r line; do
printf "IFS space quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
printf '%s\n' "Values unquoted :" # Now with values unquoted:
printf "%s\n" "$a" | while IFS='x' read -r line; do
printf "IFS --x-- unquoted : "
printf "%s, " $line; printf "%s," $line |xxd -p; done
printf "%s\n" "$a" | while IFS='' read -r line; do
printf "IFS null unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
printf "%s\n" "$a" | while IFS="$defIFS" read -r line; do
printf "IFS defau unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
unset IFS; printf "%s\n" "$a" | while read -r line; do
printf "IFS unset unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
IFS="$defIFS" # set IFS back to default.
printf "%s\n" "$a" | while IFS=' ' read -r line; do
printf "IFS space unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
私は得る:
$ ./stackexchange-Understanding-IFS.sh
IFS value: 20090a
var value : bar baz quz -20202062617220202062617a20202071757a2020200a
IFS --x-- : bar baz quz -20202062617220202062617a20202071757a202020
Values quoted :
IFS null quoted : bar baz quz -20202062617220202062617a20202071757a202020
IFS default quoted : bar baz quz-62617220202062617a20202071757a
IFS unset quoted : bar baz quz-62617220202062617a20202071757a
IFS space quoted : bar baz quz-62617220202062617a20202071757a
Values unquoted :
IFS --x-- unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS null unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS defau unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS unset unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS space unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
最初の値はちょうどの正しい値です IFS=
'spacetabnewline'
次の行は、var $a
が持つすべての16進値と、各読み取りコマンドに与えられる最後の改行「0a」です。
IFSがヌルである次の行は「フィールド分割」を実行しませんが、改行は削除されます(予想どおり)。
次の3行は、IFSにスペースが含まれているため、最初のスペースを削除し、var行を残りのバランスに設定します。
最後の4行は、引用符で囲まれていない変数の動作を示しています。値は(複数の)スペースで分割され、次のように出力されます。bar,baz,qux,
IFS
と未設定IFS
は非常に異なります。Q4の答えは部分的に間違っています。ここでは、内側の区切り文字には触れず、先頭と末尾の区切り文字のみに触れます。