$(command $ arg)を引用する正しい方法は何ですか?


17

長年私を悩ませてきたこの難問を解決する時が来ました...

私は時々これに会ってきました、そして、これが行く方法であると思いました:

$(comm "$(arg)")

そして、私の見解は経験に強く支えられていると思いました。しかし、私はもうよくわかりません。Shellcheckでも決心することはできません。両方です:

"$(dirname $0)"/stop.bash
           ^-- SC2086: Double quote to prevent globbing and word splitting.

そして:

$(dirname "$0")/stop.bash
^-- SC2046: Quote this to prevent word splitting.

背後にあるロジックは何ですか?

(これはShellcheckバージョン0.4.4、btwです。)


1
すべての置換を引用します。
イグナシオバスケス-エイブラムス

3
このように:"$(dirname "$0")"/stop.bash?うまくいくようです...ストーリーは何ですか?
トマス

1
bashは、コンテキストがいつ変更されたかを知るのに十分スマートです。
イグナシオバスケス-エイブラムス

1
このようにそれについて考える:shell_level_1 $(shell_level_2) shell_level_1:あなたが内部にあるとき$(....)(すなわち、あなたが直接書き込むことができますが、シェルの「サブレベル」を入力し、しかし、あなたは主のレベルにあったかのようにあなたはそれに書くことができる"代わりに、\"など、)。例: touch "/tmp/a file" ; echo "its size is: $(find "/tmp/a file" -ls | awk '{print $5}) ..." : if you used backticks you'd have to \ "/ tmp / a file \" `およびprint \$5$(...)必要はありません:シェル新たなレベルに適応し、あなたのインタプリタは今、あまりにもそのレベルにあるかのようにあなたが直接書き込むことができます。
オリビエデュラック

「シェルチェックも決心できません。」-2つの実行には2つの異なるメッセージがあり、異なる場所を指します。両方が必要です。
イズカタ

回答:


45

を使用する必要があります"$(somecmd "$file")"

引用符がない場合、スペースを含むパスはの引数で分割されsomecmd、間違ったファイルをターゲットにします。そのため、内側に引用符が必要です。

の出力にスペースが含まれていると、somecmd分割が発生するため、コマンド置換全体の外側に引用符が必要です。

コマンド置換内の引用符は、それ以外の引用符には影響しません。Bash自身のリファレンスマニュアルはこれについてあまり明確ではありませんが、BashGuideが明示的に言及しています。「有効なシェルスクリプト」は内部で許可されているため、POSIXテキストでも必要です$(...)

この$(command)フォームでは、開き括弧から対応する閉じ括弧までのすべての文字がコマンドを構成します。任意の有効なシェルスクリプトをコマンドに使用できますが、不特定の結果を生成するリダイレクトのみで構成されるスクリプトを除きます。


例:

$ file="./space here/foo"

a。引用符なし、dirname両方./spaceを処理し、here/foo

$ printf "<%s>\n" $(dirname $file)
<.>
<here>

b。dirnameプロセス内の引用./space here/foo、与える./space here、これは2つに分割されます:

$ printf "<%s>\n" $(dirname "$file")
<./space>
<here>

c。外部で引用し、dirname両方./spaceを処理し、とhere/fooを別々の行に出力しますが、2行が1つの引数を形成します

$ printf "<%s>\n" "$(dirname $file)"
<.
here>

d。内側と外側の両方を引用すると、正しい答えが得られます。

$ printf "<%s>\n" "$(dirname "$file")"
<./space here>

dirname最初の引数のみを処理した場合、それはおそらく簡単だったでしょうが、ケースaとcの違いを示していません。)

dirname(場合によっては)を追加する必要があることに注意してください。--これは、ダッシュで始まる場合にファイル名がオプションとして使用されないようにするため"$(dirname -- "$file")"です。


16
注:一般に、引用符はbashにネストされません。ただし、この場合、は$( )新しいコンテキストを作成するため、内部の引用は外部の引用から独立しています。また、通常、両方のコンテキストで引用符が必要です。
ゴードンデイヴィ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.