私はいくつかのbashスクリプトを持っていますが、そのスクリプトには次の内容があります。
#!/bin/bash
source $(dirname ${BASH_SOURCE[0]})/script.sh
もう一方には次の内容があります。
#!/bin/bash
source "$(dirname ${BASH_SOURCE[0]})/script.sh"
これらのスクリプトの動作はどのように異なり、その理由は何ですか? is違いは何ですか?
主な違いは、引用されたバージョンはシェルによるフィールド分割の対象ではないということです。
二重引用符を使用すると、コマンド展開の結果が1つのパラメーターとしてsource
コマンドに渡されます。引用符がないと、デフォルトでスペース、TAB、改行を含むIFS
の値に応じて、複数のパラメーターに分割されます。
ディレクトリ名にそのようなスペースが含まれていない場合、フィールド分割は発生しません。
経験則として、コマンド置換と変数展開では二重引用符を使用するのが最善です。
引用符がない場合、文字列は 単語分割 および グロブ の対象になります。 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分割を実行する必要がある場合。空白で区切られた文字列のトークンをループします(グロビングを無効にします)。ただし、可能であれば、配列を使用してください。
おそらく最も重要な違いは、スクリプトがあるディレクトリにスペースがあるかどうかです。その場合、最初の行、つまり二重引用符のない行は失敗します。これは、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.
_