高度に投票されたワンライナーのネストされた二重引用符


20

3.5Kを超える票を含むStackOverflowの回答にDIRは、現在のbashスクリプトのディレクトリに割り当てるためのこの1つのライナーが含まれています。

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

ネストされた二重引用符に困惑しています。私が知る限り、次のフラグメントは二重引用符で囲まれています。

"$( cd "
"${BASH_SOURCE[0]}"
" && pwd )"

...そして、=$( dirnameおよび))の右側にある他のものはすべて引用符で囲まれていません つまり、2番目、4番目、および6 "番目の"文字は、それぞれ1番目、3番目、および5 番目の文字を「閉じる」と仮定します。

二重引用符で"${BASH_SOURCE[0]}"何が達成されるのか理解していますが、他の2組の二重引用符の目的は何ですか?

一方、(および高い得点にもかかわらず)上記のスニペットが正しくない場合、名目上の意図を達成する正しい方法は何ですか?

名目上の意図でpwd、最初にcd-ingの後に返された値をで返されたディレクトリに収集dirname "${BASH_SOURCE[0]}"し、cdサブシェルで-ing を実行し$PWD、親シェルのが変更されないようにします)。


1
$(...)の機能が原因です$( here, it's a subshell, but you are writing code as if you were writing it on the "first level" of the shell .... )
オリビエデュラック

dockerインストールスクリプトのためにここに来ました。ディストリビューションの名前を見つけるには:lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
David Tonhofer

行内のスペースは不要であることに注意してくださいDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"。同様に機能します。
デビッドトンホーファー

回答:


12

あなたのパズルはbash、入力をどのように(そして一般的にシェルが)解析したかについて正しくありません。に:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

最初に、二重引用符は二重引用符の内側に現れる可能性があるためbash、1つの長い文字列への代入の右側を解析します$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )

その後bash、コマンド置換の解析を開始します。開き括弧に続いて括弧を囲むすべての文字がコマンド置換内でコマンドを作成するために使用されるため、次のようになります。

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

シェルはその複合コマンドの解析を続け、それを2つの部分に分割します。

  • cd "$( dirname "${BASH_SOURCE[0]}" )"
  • pwd

次に、に同じ解析ルールを適用しますcd "$( dirname "${BASH_SOURCE[0]}" )"が、今回は二重引用符は冗長ではありませんが、意味があります。これらは$( dirname "${BASH_SOURCE[0]}" )、の結果でのフィールドの分割を防ぎ、${BASH_SOURCE[0]}(最も外側の二重引用符とは対照的に、変数の代入のRHSではを防ぐ必要split+globありません)。


この規則は、すべてのPOSIXシェルでのコマンド置換に適用されます。詳細については、POSIX仕様のToken Recognitionセクションをご覧ください。


21

1つが内側になると$(...)、クォートは最初からやり直します。

言い換えれば、"..."そして、互いに入れ子にする$(...)ことができます。プロセス置換には、1つ以上の完全な二重引用符で囲まれた文字列を含めることができます。また、二重引用符で囲まれた文字列には、1つ以上の完全なプロセス置換が含まれる場合があります。 しかし、それらはインターレースしません。 したがって、プロセス置換の内部で始まる二重引用符で囲まれた文字列は、その外側に拡張されることはありません。$(...)

だから、考慮してください:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

内部の内部$(...)は次のとおりです。

dirname "${BASH_SOURCE[0]}"

上記で${BASH_SOURCE[0]}は二重引用符で囲まれています。二重引用符で$(...)あると判断する場合、二重引用符または二重引用符以外の引用符は無関係${BASH_SOURCE[0]}です。

外側に$(...)は以下が含まれます。

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

ここでは、式$( dirname "${BASH_SOURCE[0]}" )は二重引用符で囲まれています。外側に引用符があるという事実$(...)は、内側に何があるかを考えるときは関係ありません。内側に引用符があるという事実$(...)も無関係です。

二重引用符の一致方法は次のとおりです。

ここに画像の説明を入力してください


どういう意味irrelevant?最も外側の括弧を除き、他のすべての括弧には独自の意味があります。
クオンルム

4
そして、これがバックティックを使用すべきではない理由です。引用ルールは非常に奇妙で直感的ではありません。
ワイルドカード

$(...)より強く結合する」という文"..."は意味がありません。それらは中置演算子ではなく、それらの間に階層はありません(その場合、引用符を括弧内に入れられないか、括弧が引用符内に入れられないことを意味しますが、そうではありません)。専門用語はそれ$(…)"…"ネストです。
ジル 'SO-悪であるのをやめる'

@Gillesとても良い。私はコンセプトをより良く捉えることを期待して言い直しました。
John1024
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.