シェルスクリプトが与えられるとtest.sh
for var in "$@"
do
echo "$var"
done
そして電話してくださいsh test.sh $(echo '"hello " "hi and bye"')
出力を期待した
hello
hi and bye
しかし、以下を得る:
"hello
"
"hi
and
bye"
私が次に変更した場合sh test.sh $(echo "hello " "hi and bye")
それから私は得ます
hello
hi
and
bye
これらの動作のどれも望ましくない。目的の動作を取得するにはどうすればよいですか?
私が理解したいのはなぜ同じではありませんかsh test.sh $(echo "hello " "hi and bye")
?sh test.sh "hello " "hi and bye"
答え1
コマンド置換は文字列を生成します。
の場合
$(echo '"hello " "hi and bye"')
文字列は"hello " "hi and bye"
。
その後、文字列がトークン化されます(ファイル名のグロービングも同様ですが、この例には影響しません)。トークン化は、文字の1つと同じすべての文字$IFS
(デフォルトでは空白、タブ、および改行)で発生します。
デフォルト値は、、、、および単語IFS
を"hello
生成"
します。 "hi
and
bye"
その後、スクリプトに別々のパラメーターとして提供します。
2番目のコマンドでは、コマンドの置き換えは次のようになります。
$(echo "hello " "hi and bye")
その後、文字列が生成され、トークン化は、、、およびhello hi and bye
4つの単語を生成します。hello
hi
and
bye
最後の例では二つパラメータを使用hello
し、hi and bye
スクリプトと共に直接使用されます。これらに慣れる単語の分割は引用されているために発生します。
答え2
長い話を短く:の結果はecho
結果分割の犠牲者$()
であり、sh test.sh "hello " "hi and bye"
他の規則を使用します。
set -x
デバッグを追加するときに実際に何が起こるのか見てみましょう。
> set -x
> ./main.sh $(echo '"hello " "hi and bye"')
++ echo '"hello " "hi and bye"'
+ ./main.sh '"hello' '"' '"hi' and 'bye"'
"hello
"
"hi
and
bye"
echo
"hello " "hi and bye"
これは、コマンド自体の一重引用符のため、単一の引数(たとえば、すべてのスペースと一重引用符を含む)で受け取ります。ただし、コマンド置換はこれを"hello " "hi and bye"
.dereferenceに置き換えます。バッシュマニュアル:
二重引用符で置換が発生すると、単語の区切りとパス名の拡張は行われません。結果について。
ただし、引用符なしでコマンドを置き換えると、$IFS
空白文字(単語分割用の変数に設定されている3文字のうちの1つ)に基づいて単語分割が許可されます。したがって、結果の文字列をすべてのスペースで破棄すると何が得られますか?
"hello
、空白、その後に次のトークンがあります。"
- 両側にスペースで区切られた文字自体です。"hi
、再び左と右にスペースがあります。and
bye"
全体的に空白のために破損した5つのトークンが得られます。この場合、噴射は正確に命令置換の結果であることを認識することが重要である。その後、それらはすべて解析された個々のトークンとして扱われます。set -x
出力が示すように、シェルスクリプトはこれらのタグを使用して呼び出されます。
パフォーマンスが異なる理由は、適用されるルールが異なるsh test.sh "hello " "hi and bye"
ためです。入力したコマンドラインは入力と同時に解析され、引用符付き文字列は単一の単位として扱われますhello
。hi and bye
答え3
スペース以外のものに変更することができますIFS
( のスペースを保護するためhi and bye
)。これを使用して2つの文字列を区切ります。
$ IFS=:
$ sh test.sh $(echo "hello ":"hi and bye")
hello
hi and bye
(とにかくこの例に関連する)操作の順序は次のとおりです。
- 変える
- 噴射
- 見積もりの削除
代替結果として生成された引用符は、トークン化または引用符の削除に関して特別ではないため、(1)出力の引用符は他の文字と同様に(2)と(3)を通過します。だから:
echo "hello " "hi and bye"
シェルはこれらの引用符を削除してecho
sumhello
とhi and bye
出力を取得し、文字列をスペースでhello hi and bye
連結します。echo '"hello " "hi and bye"'
シェルは外側を取り除き、echo'
はそれを取り出して"hello " "hi and bye"
出力します。コマンド置換では で
sh test.sh $(echo '"hello " "hi and bye"')
置き換えられますが"hello " "hi and bye"
これら引用符は置換の結果であるため、単語の区切りや引用符の削除は不要です。したがって、シェルはこれを、、、、
"hello
に分割して出力します。"
"hi
and
bye"
- では、
sh test.sh $(echo "hello " "hi and bye")
コマンド置換がで置き換えられ、これは、およびに分割hello hi and bye
されます。hello
hi
bye
答え4
どうですか?
sh test.sh "hello " "hi and bye"
?