読んでこの行を見ました。IFSに関するブログそれは:
for i in $(<test.txt)
そして、$(<test.txt)
ファイルの内容をSTDOUTに印刷することを考えてみましょう。私は間違っているかもしれませんが、好奇心が強いので、シェルでこれを試してみました。したがって、array
任意のデータで名前が付けられた任意のファイルが選択され、
まず、1つを実行すると、cat array
次のような結果が出ました。
amit@C0deDaedalus:~/test$
amit@C0deDaedalus:~/test$ cat array
1) Ottawa Canada 345644
2) Kabul Afghanistan 667345
3) Paris France 214423
4) Moscow Russia 128793
5) Delhi India 142894
それから$(<array)
私には次のものが与えられます。
amit@C0deDaedalus:~/test$ $(<array)
1) Ottawa Ca: command not found
入力リダイレクトに使用されることだけがわかりますが、<
シェルがここでこれをコマンドとして解釈するものが何であるかを正確には知りません。
シェルでこの奇妙な出力の背後にある概念を説明できる人はいますか?
直す:-
実行すると、set -x
次のようになります。
amit@C0deDaedalus:~/test$ $(<array)
+ '1)' Ottawa Canada 345644 '2)' Kabul Afghanistan 667345 '3)' Paris France 214423 '4)' Moscow Russia 128793 '5)' Delhi India 142894
+ '[' -x /usr/lib/command-not-found ']'
+ /usr/lib/command-not-found -- '1)'
1): command not found
+ return 127
amit@C0deDaedalus:~/test$
答え1
この$(command)
構文はサブシェル環境で実行され、command
独自にandに置き換えられますcommand
。Bashのマニュアルによると、$(< file)
単により速いようです$(cat file)
(しかし、POSIX機能ではありません)。
したがって、を実行すると、$(<array)
Bashはその置換を実行し、最初のフィールドをコマンド名として使用し、残りのフィールドをコマンドの引数として使用します。
$ $(<array)
1): command not found
コマンド/機能がないため、1)
エラーメッセージが表示されます。
ただし、特定のシナリオではIFS変数を変更したため、他のエラーメッセージが表示されることがあります。
$ IFS=n; $(<array)
1) Ottawa Ca: command not found
編集1
私の考えでは、あなたのIFS
コードが修正されたので、シェルが代わり1) Ottawa Ca
に実行しようとすることです1)
。結局、あなたはIFS
関連記事を読んでいます。IFS
奇妙な値が出ても驚かないでしょう。
このIFS
変数はいわゆる噴射またはフィールド分割。これは、デフォルトでシェルが拡張コンテキスト(または他のコマンドなど)でデータを解析する方法を定義しますread
。
3.5.7 噴射
シェルは、単語分割のために二重引用符内に表示されない引数拡張、コマンド置換、および算術拡張の結果をスキャンします。
シェルは各文字を
$IFS
区切り文字として扱い、これらの文字をフィールド終端として使用して、他の拡張結果を単語に分割します。設定されていIFS
ない場合、またはその値がデフォルト値の場合<space><tab><newline>
、前の拡張結果の先頭と末尾にある、およびのシーケンスは無視され、<space>
開始<tab>
または終了以外の文字シーケンスは単語を区切るために使用されます。デフォルト以外の値を使用すると、空白文字が(空白)値内にある限り、単語の先頭と末尾の空白文字、、、およびシーケンスは無視されます。空白以外の文字に隣接する空白文字は別のフィールドです。空白文字シーケンスも区切り文字と見なされます。値が空の場合、単語分割は発生しません。<newline>
IFS
IFS
space
tab
newline
IFS
IFS
IFS
IFS
IFS
IFS
IFS
明示的な空の引数(
""
または''
)は保持され、空の文字列としてコマンドに渡されます。値のないパラメータ拡張により、暗黙的に引用されていないNULLパラメータは削除されます。値のない引数を二重引用符で拡張すると、空の引数が生成されます。これは保持され、空の文字列としてコマンドに渡されます。 NULL以外の拡張単語の一部として引用されたNULL引数が発生すると、NULL引数は削除されます。つまり、単語の分割と空のパラメータの削除後にその単語になります-d''
。-d
拡張が発生しない場合、分割は行われません。
IFS
以下は、コマンドの代替使用のいくつかの例です。
例1:
$ IFS=$' \t\n'; var='hello world'; printf '[%s]\n' ${var}
[hello]
[world]
$ IFS=$' \t\n'; var='hello world'; printf '[%s]\n' "${var}"
[hello world]
どちらの場合も、IFS
is <space><tab><newline>
(デフォルト)、var
is、hello world
およびステートメントがありますprintf
。ただし、最初のケースでは単語の区切りが行われますが、2番目のケースではそうではありません(二重引用符がその動作を抑制するため)。非参照拡張ではトークン化が発生します。
例2:
$ IFS='x'; var='fooxbar'; printf '[%s]\n' ${var}
[foo]
[bar]
$ IFS='2'; (exit 123); printf '[%s]\n' ${?}
[1]
[3]
空白文字もなく、空白文字も含まれていないため、${var}
この${?}
場合、単語分割が問題にならないと考えることもできます。ただし、これは乱用される可能性があるため、そうではありませんIFS
。IFS
ほぼすべての価値を保存し、簡単に乱用することができます。
例3:
$ $(echo uname)
Linux
$ $(xxd -p -r <<< 64617465202d75)
Sat Apr 28 12:46:49 UTC 2018
$ var='echo foo; echo bar'; eval "$(echo "${var}")"
foo
bar
これはトークン化とは関係ありませんが、コードを挿入するためにいくつかの汚いトリックを使用する方法に注意してください。
関連質問: