web-dev-qa-db-ja.com

bashに二重引用符があるかどうかの違いは何ですか

私はいくつかのbashスクリプトを持っていますが、そのスクリプトには次の内容があります。

#!/bin/bash
source $(dirname ${BASH_SOURCE[0]})/script.sh

もう一方には次の内容があります。

#!/bin/bash
source "$(dirname ${BASH_SOURCE[0]})/script.sh"

これらのスクリプトの動作はどのように異なり、その理由は何ですか? is違いは何ですか?

8
Alex

主な違いは、引用されたバージョンはシェルによるフィールド分割の対象ではないということです。

二重引用符を使用すると、コマンド展開の結果が1つのパラメーターとしてsourceコマンドに渡されます。引用符がないと、デフォルトでスペース、TAB、改行を含むIFSの値に応じて、複数のパラメーターに分割されます。

ディレクトリ名にそのようなスペースが含まれていない場合、フィールド分割は発生しません。

経験則として、コマンド置換と変数展開では二重引用符を使用するのが最善です。

7
Scrutinizer

引用符がない場合、文字列は 単語分割 および グロブ の対象になります。 BashPitfalls#14 も参照してください。

比較する

_$ echo $(printf 'foo\nbar\nquux\n*')
foo bar quux ssh-13yzvBMwVYgn ssh-3JIxkphQ07Ei ssh-6YC5dbnk1wOc 
_

_$ echo "$(printf 'foo\nbar\nquux\n*')"
foo
bar
quux
*
_

Word分割が発生すると、IFSの最初の文字が区切り文字(デフォルトではスペース)として機能します。

ほとんどすべての状況で、引用符を追加する必要があります。いくつかの例外があります。

  • 単純な(配列以外の)割り当てやcaseステートメントなど、単語の分割/グロブが発生しない式。以下はすべて安全です。

    • _foo=*_
    • _foo=${bar}qux${quux}_
    • foo=$(bar "${quux}")
    • _case ${var} in_

    ただし、これはそうではありません(あなたが探しているのがリテラルのアスタリスク文字を持つ単一の要素である場合):

    • foo=( * )
  • 具体的には、Word分割を実行する必要がある場合。空白で区切られた文字列のトークンをループします(グロビングを無効にします)。ただし、可能であれば、配列を使用してください。

12

おそらく最も重要な違いは、スクリプトがあるディレクトリにスペースがあるかどうかです。その場合、最初の行、つまり二重引用符のない行は失敗します。これは、bashが引用符で囲まれていない文字列に対して行う「単語分割」の結果です。

_dirname ${BASH_SOURCE[0]}_の結果が_/home/j r/bin_であるとします。引用符のない行を考えてみましょう:

_source $(dirname ${BASH_SOURCE[0]})/script.sh
_

この場合、bashは次のコマンドを参照します。

_source /home/j r/bin/script.sh
_

単語分割後、sourceコマンドはスクリプト名_/home/j_とスクリプトへの引数_r/bin/script.sh_を確認します。おそらく、その名前のスクリプトはなく、bashはエラーメッセージを返します。

_bash: /bin/j: No such file or directory
_

次に、二重引用符で何が起こるかを考えます。

_source "$(dirname ${BASH_SOURCE[0]})/script.sh"
_

この場合、sourceコマンドは_/home/j r/bin/script.sh_という名前のスクリプトを探し、それをソースにしようとします。

完全を期すために、一重引用符を考えてみましょう。

_source '$(dirname ${BASH_SOURCE[0]})/script.sh'
_

この場合、前の2つとは異なり、dirnameは実行されません。 sourceコマンドは、リテラル名$(dirname ${BASH_SOURCE[0]})/script.shでコマンドをソースしようとします。おそらくそのようなファイルはなく、bashはエラーメッセージを出力します。

Bashが文字列を二重引用符で処理する方法については、_man bash_で詳しく説明しています。

_  Enclosing characters in double quotes preserves the  literal  value  of
   all  characters  within the quotes, with the exception of $, `, \, and,
   when history expansion is enabled, !.  The characters $  and  `  retain
   their  special meaning within double quotes.  The backslash retains its
   special meaning only when followed by one of the following  characters:
   $,  `,  ", \, or <newline>.  A double quote may be quoted within double
   quotes by preceding it with a backslash.  If enabled, history expansion
   will  be  performed  unless an !  appearing in double quotes is escaped
   using a backslash.  The backslash preceding the !  is not removed.
_
4
John1024