シェルスクリプトがテキストを引用するこれらのさまざまな方法をすべて使用しているのを時々目にします: "..."
、'...'
、 $'...'
、および $ "..."
。なぜこれほど多くの種類の見積もりが使用されているのですか?
それらは異なった振る舞いをしますか、それとも私がそれらの中でできることに影響を与えますか?
承認された回答:
これらはすべて異なる意味を持ち、その中に異なるもの(または同じもの、異なる意味)を書くことができます。さまざまな種類の引用符は、その中のさまざまなエスケープシーケンスを解釈します(何か
)、または変数の補間を許可するか許可しないか( $ something
)およびそれらの内部の他の種類の拡張。
要するに:
-
'...'
完全に文字通りです。 -
"..."
変数と埋め込み引用文字の両方を許可します。 -
$'...'
n
のような文字エスケープを実行します 、ただし変数は展開しません。 -
$ "..."
Bashとkshでの人間の言語の翻訳用です。
「一重引用符」
一重引用符の間に書いたものはすべて文字通りに扱われ、まったく処理されません。バックスラッシュとドル記号には、特別な意味はありません。つまり、文字(他の一重引用符を含む)をバックスラッシュでエスケープしたり、変数を補間したり、他のシェル機能を使用したりすることはできません。
これらの例はすべて、文字通り引用符の間に書かれているものになります:
コード | 結果 |
---|---|
'hello world' | hello world |
'/ pkg / bin:$ PATH' | / pkg / bin:$ PATH |
'hellonworld' | hellonworld |
'`echo abc`' | `echo abc` |
'I'dn't've' | 未確認 |
最後の1つは複雑です–2つあります 一重引用符で囲まれた文字列は、引用符で囲まれていないテキストと一緒に実行されます。最初のものにはI
が含まれています 。引用符で囲まれていないテキストはしません
シェルレベルでエスケープされた一重引用符が含まれています 、したがって、引用符で囲まれた文字列を開始せず、リテラル文字として含まれます(つまり、しない
)。最後に引用される文字列は、 ve
です。 。これらはすべて、シェルが機能する通常の方法で1つの単語にまとめられます。
リテラルテキストと変数を組み合わせるためのやや一般的なイディオムは、次のようにそれらを一緒に実行することです。
'let x="'$PATH"
結果は
になりますlet x="/usr/bin:/bin"
1つの単語として( $ PATH
を二重引用符で囲む方がよい 念のために–変数 value内のスペースまたはグロビング文字 他の方法で処理される可能性がありますが、読みやすい実行例のために、私はしていません。
「二重引用符」
二重引用符の中には、2種類の展開が処理されます。バックスラッシュを使用して文字をエスケープし、展開またはエスケープが処理されないようにすることができます。
二重引用符で囲まれた拡張には、次の2つのカテゴリがあります。
-
$
で始まるもの (パラメータ展開$ abc
および${abc}
、コマンド置換$(...)
、および算術展開$((...))
); - バッククォートによるコマンド置換
`abc`
;
引用符の内側では、バックスラッシュを $
の前に置くことで、これらの展開を禁止できます。 または`
。終了の二重引用符をエスケープすることもできるため、 "
"
だけが含まれます 文字列、または別のバックスラッシュで。その他のバックスラッシュは文字通り保持されます。他の文字を生成するためのエスケープはなく、削除されません。
これらの例の中には、以前とは動作が異なるものとそうでないものがあります。
コード | 結果 |
---|---|
"hello world" | hello world |
"/ pkg / bin:$ PATH" | / pkg / bin:/ bin:/ usr / bin |
"hellonworld" | hellonworld |
"hello \ nworld" | hellonworld |
"` echo abc` " | abc |
"I'dn't've" | 私はしていません |
"I'dn't've" | 私はしていません |
"I" dn "t've" | 私はしませんでした |
$’ANSI-C quoting’
この種の引用では、Cスタイルのバックスラッシュエスケープを処理できますが、 埋め込まれた変数または置換。 これはのみです 文字エスケープをサポートする一種の引用 。
これはkshからの拡張であり、Bash、zsh、およびその他のいくつかのシェルでもサポートされるようになりました。これはまだPOSIX標準の一部ではないため、最大限に移植可能なスクリプトでは使用できませんが、Bashまたはkshスクリプトは無料で使用できます。
これらのエスケープはすべて、Cの意味で使用できます: a
、 b
、 f
、 n
、 r
、 t
、 v
、およびリテラルは \
をエスケープします 、'
、"コード> 、および
?
。また、拡張機能 e
もサポートしています。 (エスケープ文字)およびBashとksh cx
(Ctrl-xで入力される内容(例: cM
) キャリッジリターンです)。シェルには、独自のマイナーな拡張機能があります。
また、4種類の一般的な文字エスケープを許可します:
-
nnn
、8進値の1バイト nnn -
xHH
、16進値の1バイト HH -
uHHHH
、16進インデックスが HHHHであるUnicodeコードポイント -
UHHHHHHHH
、16進インデックスが HHHHHHHHであるUnicodeコードポイント
これらの数字はすべて、最初の数字の後はオプションです。
$
および`
意味がなく、文字通り保存されるため、そこに変数を含めることはできません。
コード | 結果 |
---|---|
$'hello world' | hello world |
$'/ pkg / bin:$ PATH' | / pkg / bin:$ PATH |
$'hellonworld' | こんにちは 世界 |
$'`echo abc`' | `echo abc` |
$'私は'していません' | 私はしていません |
$'U1f574u263A' | 🕴☺ |
printf
を使用してシミュレートできるこれらのエスケープのほとんどは、 コマンド、ただしPOSIXは \
のみを必要とします 、 a
、 b
、 f
、 n
、 r
、 t
、 v
、および nnn
そこで働くために。コマンド置換を使用して、 printf
を埋め込むことができます 必要に応じて二重引用符で囲みます: "Path:$(printf't')$ PATH"
。
$”ロケールの翻訳”
これは、自然言語のテキスト文字列をローカライズするためのkshおよびBash固有の拡張機能であり、メッセージカタログの引用符内の部分を検索します。最初にすべての二重引用符の展開を実行します。文字列が翻訳データベースに見つからない場合は、独自の翻訳として使用されます。組み込みの前提は、文字列が英語であるということです。
これはおそらく使用したくないでしょうが、表示された場合は通常、通常の二重引用符として扱うことができます。
注意点の1つは、がないことです。 埋め込まれたパラメータの拡張と埋め込まれた文字のエスケープの両方を可能にする一種の引用。それが必要なほとんどの場合、 printf
を使用したほうがよい(より安全)でしょう。 :
printf 'New path: e[1m%se[0m' "/pkg/bin:$PATH:"
これにより、どの部分が文字エスケープの対象になり、どの部分がデータ値になるかが明確に区別されます。
もう1つは、これらの引用スタイルはすべて、シェルに1つの「単語」を作成することです。 [メール保護]
または配列展開${x [@]}
二重引用符で囲んで使用されます。両方の一重引用符の形式は常に1つの単語であり、それ以上拡張されることはありません。