web-dev-qa-db-ja.com

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

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

私は時々これに会っていて、これが行く方法だと思っていました:

$(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です。)

17
user147505

"$(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")"

45
ilkkachu