1. 序章

Linuxエコシステムの初心者として、私たちがオンラインで読んだいくつかのコマンドで議論に出くわすかもしれません。 これらの引数を二重引用符で囲む場合もあれば、一重引用符で囲む場合もありますが、まったく引用符で囲まない場合もあります。 この記事では、さまざまな引用符が使用または省略される可能性のあるさまざまなシナリオを見て、引用符がどのように機能するかを理解します。

2. 空白のある文字列

シナリオで、空白を含むリテラル文字列または引数がある場合、一重引用符または二重引用符を使用して文字列全体をラップし、単一の引数であるかのように処理できます。 exprコマンドを使用してこれを試すことができます。

$ expr length "hello world"
11
$ expr length 'hello world'
11
$ expr length hello world
expr: syntax error: unexpected argument ‘world’

一重引用符または二重引用符を使用する場合、「hello world」は単一の引数として扱われ、lengthは11と評価されます。 引用符を省略すると、「hello」と「world」は別々の引数として扱われ、 length 操作には1つの引数しか期待されないため、コマンドはエラーをスローします。

3. 変数補間の制御

変数の補間は、二重引用符を使用するか、引用符を省略すると発生します。 変数の補間を抑制する必要がある場合は、引数を一重引用符で囲みます。いくつかの例を使用して、これが実際に動作していることを確認できます。

$ a=hello
$ b=world
$ echo $a
hello
$ echo "$a"
hello
$ echo "$a $b"
hello world
$ echo '$a $b'
$a $b

上記の例では、「a」と「b」の2つの変数を定義しており、二重引用符を使用するか引用符を省略すると、それらの値が置き換えられることがわかります。 一重引用符を使用する場合、置換が行われないため、変数名は逐語的に出力されます。

4. コマンドの置換

変数の補間と同様に、コマンド置換は、二重引用符で囲むか、引用符を省略した場合にのみ機能します。 一重引用符は、引数を逐語的に取ります。 これがどのように機能するかを確認するために、いくつかのコマンドを試してみましょう。

$ echo "$(ls /usr/share/dict)"
american-english
british-english
README.select-wordlist
words
words.pre-dictionaries-common
$ echo $(ls /usr/share/dict)
american-english british-english README.select-wordlist words words.pre-dictionaries-common
$ echo '$(ls /usr/share/dict)'
$(ls /usr/share/dict)

上記の例から、二重引用符を使用したり、引用符を省略したりすると、中括弧で囲まれたコマンドが実行され、結果が出力されることがわかります。 一重引用符を使用すると、コマンドは実行されませんが、引数は逐語的に出力されます。

5. ファイルグロブの制御

一重引用符または二重引用符を使用して、ファイルのグロブを抑制することができます。 ファイルグロブを機能させる必要がある場合は、引用符を省略する必要があります

$ cat *
file1 contents
file2 contents
file3 contents
$ cat "*"
cat: '*': No such file or directory
$ cat '*'
cat: '*': No such file or directory
$ cat "my dir/"*
file1 contents
file2 contents
file3 contents
$ cat my dir/*
cat: my: No such file or directory
cat: 'dir/*': No such file or directory

上記の例から、空白を引用符で囲み、ワイルドカード文字を引用符の外側に配置してグロビングを実行できることにも注意してください。 これは、一重引用符と二重引用符の両方で機能します。

6. 引用符と特殊文字の保護

二重引用符を保護するために一重引用符を使用する場合があり、その逆もあります

$ echo he'll'o
hello
$ echo he"ll"o
hello
$ echo 'he"ll"o'
he"ll"o
$ echo "he'll'o"
he'll'o

上記の例では、文字列全体が引用符で囲まれている場合にのみ、文字列内の引用符が保持されることがわかります。 また、一重引用符の前に$記号を含めて、エスケープシーケンスをその意味に従って解釈するオプションもあります。 さらに、これを使用して、同じ文字列内の単一引用符と二重引用符を保護できます。

$ echo "hello\nworld"
hello\nworld
$ echo 'hello\nworld'
hello\nworld
$ echo $'hello\nworld'
hello
world
$ echo $'\'single quoted text\' and "double quoted text"'
'single quoted text' and "double quoted text"

7. 単語分割の制御

単語分割を実行するには、引用符を省略する必要があります。引用符を追加すると、分割は発生せず、文字列全体が1つの単位として処理されます。

$ for word in one two three; do echo $word; done
one
two
three
$ for word in "one two three"; do echo $word; done
one two three
$ for word in 'one two three'; do echo $word; done
one two three

前者の場合、単語の分割が発生して3つの単語が生成されるため、ループは3回実行されますが、後者の場合、ループは文字列全体を値として1回だけ実行されます。

8. 結論

この記事では、3種類の引用符の引数のさまざまな効果と、引用符を使用しない場合に何が起こるかについて説明しました。 クイックリファレンスのために以下の要点をまとめましょう

シナリオ 二重引用符 一重引用符 引用なし
引数で許可される空白 はい はい いいえ
可変補間 はい いいえ はい
コマンドの置換 はい いいえ はい
ファイルグロブ いいえ いいえ はい
単語分割 いいえ いいえ はい
見積もり保護 一重引用符 二重引用符 なし

文字列内の単一引用符と二重引用符の両方を保護する必要がある場合は、エスケープシーケンスとともにシェル引用符を使用できることに注意してください。