Bashでの一重引用符と二重引用符の違い


回答:


579

一重引用符は何も補間しませんが、二重引用符は補間します。例:変数、バックティック、特定の\エスケープなど。

例:

$ echo "$(echo "upg")"
upg
$ echo '$(echo "upg")'
$(echo "upg")

Bashのマニュアルにはこう書いてある:

3.1.2.2単一引用符

文字を一重引用符で囲む(')、引用符内の各文字のリテラル値が保持されます。バックスラッシュが前に付いていても、一重引用符は一重引用符の間に出現しない場合があります。

3.1.2.3二重引用符

(二重引用符で文字を囲む")を除いて、全ての文字のリテラル値を保持し$`\、履歴展開が有効になっている場合、および!。文字$`は、二重引用符内で特別な意味を保持します(シェル展開を参照)。バックスラッシュは、次の文字のいずれかが続く場合にのみその特別な意味を保持し:$`"\、または改行。二重引用符内では、これらの文字のいずれかが後に続くバックスラッシュが削除されます。特別な意味のない文字の前のバックスラッシュは変更されません。二重引用符は、バックスラッシュを前に付けることにより、二重引用符で囲むことができます。有効に!すると、二重引用符で囲まれた箇所がバックスラッシュを使用してエスケープされない限り、履歴の展開が実行されます。の前のバックスラッシュ!は削除されません。

特別なパラメーターは、二重引用符で囲まれたときに特別な意味*@持ちます(シェルパラメーターの展開を参照)。


41
「補間」の意味がわからない場合:en.wikipedia.org/wiki/String_interpolation
Kolob Canyon

あなたが使用している場合についてはgit_prompt、彼らはこのようにそれを使用することをお勧めことはgitを提供しPS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ 'gitのプロンプト、これは仕事ではないはずによります。PS#変数について何か特別なことはありますか?または、補間を行わない場合に機能するのはなぜですか。
ekiim

@ekiimその正確なテキストは(変更されていない)に設定されPS1ます。echo $PS1私が何を意味するか見てみてください。ただしPS1、表示される前に評価されます(PROMPTINGbashマンページのセクションを参照)。これをテストするには、を試してくださいPS1='$X'。プロンプトは表示されません。次に実行するX=fooと、突然プロンプトが「foo」になります(設定PS1されたときに表示さずに評価された場合、プロンプトは表示されません)。
Adam Batkin

262

受け入れ答えは素晴らしいです。トピックをすばやく理解するのに役立つ表を作成しています。説明には、単純な変数aとインデックス付き配列が含まれますarr

設定したら

a=apple      # a simple variable
arr=(apple)  # an indexed array with a single element

次にecho2列目の式では、3列目に示す結果/動作が得られます。4列目は動作を説明しています。

 # | Expression  | Result      | Comments
---+-------------+-------------+--------------------------------------------------------------------
 1 | "$a"        | apple       | variables are expanded inside ""
 2 | '$a'        | $a          | variables are not expanded inside ''
 3 | "'$a'"      | 'apple'     | '' has no special meaning inside ""
 4 | '"$a"'      | "$a"        | "" is treated literally inside ''
 5 | '\''        | **invalid** | can not escape a ' within ''; use "'" or $'\'' (ANSI-C quoting)
 6 | "red$arocks"| red         | $arocks does not expand $a; use ${a}rocks to preserve $a
 7 | "redapple$" | redapple$   | $ followed by no variable name evaluates to $
 8 | '\"'        | \"          | \ has no special meaning inside ''
 9 | "\'"        | \'          | \' is interpreted inside "" but has no significance for '
10 | "\""        | "           | \" is interpreted inside ""
11 | "*"         | *           | glob does not work inside "" or ''
12 | "\t\n"      | \t\n        | \t and \n have no special meaning inside "" or ''; use ANSI-C quoting
13 | "`echo hi`" | hi          | `` and $() are evaluated inside ""
14 | '`echo hi`' | `echo hi`   | `` and $() are not evaluated inside ''
15 | '${arr[0]}' | ${arr[0]}   | array access not possible inside ''
16 | "${arr[0]}" | apple       | array access works inside ""
17 | $'$a\''     | $a'         | single quotes can be escaped inside ANSI-C quoting
18 | "$'\t'"     | $'\t'       | ANSI-C quoting is not interpreted inside ""
19 | '!cmd'      | !cmd        | history expansion character '!' is ignored inside ''
20 | "!cmd"      | cmd args    | expands to the most recent command matching "cmd"
21 | $'!cmd'     | !cmd        | history expansion character '!' is ignored inside ANSI-C quotes
---+-------------+-------------+--------------------------------------------------------------------

以下も参照してください。


1
受け入れられた答えは最後に言うThe special parameters * and @ have special meaning when in double quotesので、どうして"*"結果は*どうなるのですか?
anddero 2018年

2
@ Karl-AnderoMere。その場合、それらはパラメーターとしてまったく展開されません。"$@"および"$*"パラメータ拡張です。"@"あり"*"ません。
Charles Duffy

@CharlesDuffyありがとう、それは今では理にかなっています!
anddero

3
番号9はecho "\'"、私を返します\'
MaxGyver 2018年

@MaxGyver:指摘してくれてありがとう。答えを更新しました。
codeforester 2018年

233

何かをエコーするときに何が起こるかを参照している場合、一重引用符はそれらの間にあるものを文字通りエコーし、二重引用符はそれらの間の変数を評価して変数の値を出力します。

たとえば、これ

#!/bin/sh
MYVAR=sometext
echo "double quotes gives you $MYVAR"
echo 'single quotes gives you $MYVAR'

これを与えるでしょう:

double quotes gives you sometext
single quotes gives you $MYVAR

11

他の人は非常によく説明し、単純な例を挙げたいだけです。

シェルが特殊文字を解釈しないようにするために、テキストを単一引用符で囲むことができます。単一引用符で囲まれている場合、ドル記号、スペース、アンパサンド、アスタリスク、およびその他の特殊文字はすべて無視されます。

$ echo 'All sorts of things are ignored in single quotes, like $ & * ; |.' 

これは次のようになります。

All sorts of things are ignored in single quotes, like $ & * ; |.

一重引用符で囲むことができない唯一のものは一重引用符です。

重引用符は、シェルがドル記号、逆引用符、バックスラッシュを解釈できることを除いて、単一引用符と同様に機能します。バックスラッシュが単一の特殊文字の解釈を妨げることはすでに知られています。変数の代わりにドル記号をテキストとして使用する必要がある場合は、二重引用符で囲むと便利です。また、二重引用符をエスケープして、引用符付き文字列の終わりと解釈されないようにすることもできます。

$ echo "Here's how we can use single ' and double \" quotes within double quotes"

これは次のようになります。

Here's how we can use single ' and double " quotes within double quotes

また、引用符で囲まれた文字列の先頭として解釈されるアポストロフィは、二重引用符内では無視されることにも注意してください。ただし、変数は解釈され、二重引用符で囲まれた値に置き換えられます。

$ echo "The current Oracle SID is $ORACLE_SID"

これは次のようになります。

The current Oracle SID is test

逆引用符は、一重引用符や二重引用符とはまったく異なります。特殊文字の解釈を防ぐために使用されるのではなく、逆引用符は実際にそれらが囲むコマンドの実行を強制します。囲まれたコマンドが実行された後、その出力は元の行の逆引用符の代わりに置き換えられます。これは例でより明確になります。

$ today=`date '+%A, %B %d, %Y'`
$ echo $today 

これは次のようになります。

Monday, September 28, 2015 

3

' 'との使用法には明確な違いがあり" "ます。

いつ ' 'が何かの周りで使用される、「変換または翻訳」は行われません。そのまま印刷されます。

" "、それが取り巻くものは何でも、その値に「変換または変換」されます。

翻訳/変換とは、次のことを意味します。単一引用符内のすべてのものは、それらの値に「変換」されません。彼らは引用符の中にあるので、それらは取られます。例:a=23、標準出力にecho '$a'生成$aします。一方、標準出力でecho "$a"生成さ23れます。


1
「翻訳」または「変形」とはどういう意味ですか?
Nico Haase

この答えは非常に混乱し、既存の良い答えの上に何も追加されません。
codeforester 2018

2
これは、私が理解しやすいように過度に冗長ではなく、私の意見では短い簡潔な答えでした。翻訳/変換と言うとき、それらは二重引用符が変数を拡張することを意味しますが、単一引用符は変数を拡張しません。
B_e_n_n_y_

1
はい、これが最良の答えです。これは受け入れられる答えになるはずです。
Jamey Kirby

3

これは引用符を扱う際の事実上の答えなので bashであるため、シェルで算術演算子を処理する場合、上記の答えで見逃していた点をもう1つ追加します。

bashシェルは2つの方法が演算を行うサポート、によって定義さ組み込みletコマンドと$((..))オペレータ。前者は算術式を評価しますが、後者はより複雑なステートメントです。

で使用される算術式は、let他のシェルコマンドと同様に、単語分割、パス名展開されることを理解することが重要です。したがって、適切な引用とエスケープを行う必要があります。

使用するときにこの例を参照してください let

let 'foo = 2 + 1'
echo $foo
3

ここでは一重引用符を使用しても問題ありません。ここでは変数を展開する必要がないため、

bar=1
let 'foo = $bar + 1'

$bar下の単一引用符は拡張され、次のように二重引用符で囲む必要があるため、無残に失敗します。

let 'foo = '"$bar"' + 1'

これは理由の1つである$((..))必要がありますlet。は常にの使用よりも検討する必要があります。その内部では、コンテンツは単語分割の対象ではありません。前の例を使用letすると、簡単に次のように書くことができます

(( bar=1, foo = bar + 1 ))

常に$((..))単一引用符なしで使用することを忘れないでください

$((..))二重引用符で使用できますが、二重引用符が必要なコンテンツを含めることができないため、目的はありません。単一引用符で囲まれていないことを確認してください。

printf '%d\n' '$((1+1))'
-bash: printf: $((1+1)): invalid number
printf '%d\n' $((1+1))
2
printf '%d\n' "$((1+1))"
2

$((..))単一引用符で囲まれた文字列内で演算子を使用するいくつかの特別な場合があるかもしれませんが、演算子を引用符で囲まないままにするか、二重引用符で囲むように引用符を補間する必要があります。例を考えてみましょう。curlステートメント内で演算子を使用して、リクエストが行われるたびにカウンターを渡す場合は、次のようにします。

curl http://myurl.com --data-binary '{"requestCounter":'"$((reqcnt++))"'}'

内部でネストされた二重引用符の使用に注意してください。二重引用符を使用しないと、リテラル文字列$((reqcnt++))requestCounterフィールドに渡されます。


2
Charles Duffyは、ここでも二重引用符を付けるの$((...))に適しています。それは「少し」偏執的である可能性がありIFS=0、たとえばそうすることはほとんどありませんが、それは確かに不可能ではありません:)
PesaThe

レガシー$[[...]]構文もありますが、おそらくあなたはそれを忘れていたでしょう。
tripleee
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.