単一または二重括弧を使用するのは混乱しています。このコードを見てください:
dir="/home/mazimi/VirtualBox VMs"
if [[ -d ${dir} ]]; then
echo "yep"
fi
文字列にスペースが含まれていても正常に動作します。しかし、単一の角かっこに変更すると、次のようになります。
dir="/home/mazimi/VirtualBox VMs"
if [ -d ${dir} ]; then
echo "yep"
fi
それは言う:
./script.sh: line 5: [: /home/mazimi/VirtualBox: binary operator expected
私がそれを次のように変更したとき:
dir="/home/mazimi/VirtualBox VMs"
if [ -d "${dir}" ]; then
echo "yep"
fi
良い結果。何が起こっているのかを説明できる人はいますか?たとえば、"${var}"
空白による問題を回避するには、いつ変数の周りに二重引用符を指定する必要がありますか?
答え1
単一の括弧は[
実際にはコマンドのエイリアスですtest
。いいえ通事論。
単一の括弧の欠点の1つは、評価したいオペランドの1つ以上が空の文字列を返す場合、2つのオペランド(バイナリ)が必要であると文句を言うことです。これが、オペランドが空の文字列として評価されないようにするために、人々がこれを行うのを[ x$foo = x$blah ]
見る理由です。x
[[ ]]
一方、二重括弧は文法だそして[ ]
。見つかったように、「オペランドが欠落している」という問題は発生せず、Cに似た演算子の構文もさらに受け入れます>, <, >=, <=, !=, ==, &&, ||
。
私のアドバイスはこうです:あなたの通訳#!/bin/bash
者いつも使用[[ ]]
[[ ]]
すべてのPOSIXシェルがそれをサポートしているわけではありませんが、多くのシェルがそれをサポートしているzsh
ことは注目に値します。ksh
bash
答え2
この[
コマンドは一般的なコマンドです。ほとんどのシェルは効率のために組み込み関数として提供されますが、シェルの一般的な構文規則に従います。必須ではなく最後の引数としてaが必要であることを除いて、[
それとまったく同じです。test
[
]
test
二重括弧は[[ … ]]
特殊な構文です。使い方が面倒で、シェル特殊文字にいくつかの新しいアドインを許可するため、ksh(数年後[
)に導入されました。たとえば、次のように書くことができます。[
[[
[[ $x = foo && $y = bar ]]
完全な条件式はシェルによって解析されるため、whileは最初に演算子で区切られた[ $x = foo && $y = bar ]
2つのコマンドに分割されます。同様に、二重括弧を使用すると、値が;で始まるかどうかをテストするなど、パターンマッチング構文などの操作が可能です。単一の括弧内にある場合、現在のディレクトリの名前で始まるファイルのリストが展開されます。二重括弧はkshで最初に導入され、ksh、bash、zshでのみ使用できます。[ $x = foo
$y = bar ]
&&
[[ $x == a* ]]
x
a
a*
a
小さな括弧内には、他のほとんどの場所と同様に、変数置換の周りに二重引用符を使用する必要があります。これはコマンドの引数にすぎないためです(command [
)。大括弧内には二重引用符は必要ありません。シェルは単語分離やワイルドカードを実行しないからです。これは、コマンドではなく条件式を解析することです。
1つの例外は、[[ $var1 = "$var2" ]]
バイト間文字列比較を実行する場合は引用符が必要であることです。それ以外の場合は$var2
一致するパターンになります$var1
。
できないことの1つは、[[ … ]]
変数を演算子として使用することです。たとえば、以下は完全に正当ですが、ほとんど役に立ちません。
if [ -n "$reverse_sort" ]; then op=-gt; else op=-lt; fi
…
if [ "$x" "$op" "$y" ]; then …
あなたの例では
dir="/home/mazimi/VirtualBox VMs"
if [ -d ${dir} ]; then …
内部コマンドには、4つのパラメータがif
あります。シェルはそれを解析した後に何をすべきかわかりません。正しい形式のコマンドを取得するには、単語の区切りを避ける必要があります。[
-d
/home/mazimi/VirtualBox
VMs
]
-d /home/mazimi/VirtualBox
VMs
${dir}
通常、結果に対してトークン化とワイルドカードを実行したい場合を除き、常に変数とコマンドの置換の周りに二重引用符を使用します。二重引用符を使用しないのが安全な主な場所は次のとおりです。
- 割り当てでは:(しかし、
foo=$bar
例えば配列割り当て内では二重引用符が必要です。)export "foo=$bar"
array=("$a" "$b")
case
声明から:case $foo in …
;=
or演算子の右側を除く二重括弧内==
(実際にパターン一致が必要な場合を除く)[[ $x = "$y" ]]
:。
すべて二重引用符を使用することは正しいので、高度なルールをスキップして常に引用符を使用することをお勧めします。
答え3
"${var}"
たとえば、空白による問題を回避するには、いつ変数の周りに二重引用符を指定する必要がありますか?
この質問に暗示的なこと
なぜ十分ではないのですか?
${variable_name}
${variable_name}
あなたが考えるその意味ではありません...
...そうだと思うなら何もない変数値の空白または「glob」(ファイル名パターン)文字によって発生した問題を処理します。これに最適です:${variable_name}
$ bar=foo
$ bard=Shakespeare
$ echo $bard
Shakespeare
$ echo ${bar}d
food
他に何もない! 1し ないでください${variable_name}
どのA
変数名の一部である可能性がある文字(文字( -Z
またはa
- z
)、アンダースコア(_
)、または数字(0
- ))が後に来ない限り、大丈夫です9
。それにもかかわらず、問題を解決することができます。
$ echo "$bar"d
food
または
$ fourth_letter=d
$ echo $bar$fourth_letter
food
私はその使用を妨げるのではなく(
echo "${bar}d"
おそらく最善の解決策です)、人々が矯正器に依存するのを止めようとしています。変える引用符を使用するか、本能的に中括弧を使用して「今引用符が必要ですか?返品?」
妥当な理由がなく、自分がしていることを確実に知らない限り、常に引用符を使用する必要があります。
________________ 1もちろん、以下の場合は
除外されます。パラメータ拡張、、、、、などの文法は文法に基づいています。また、などを使用して10番目、11番目などの位置パラメータを引用する必要があります。 - 引用はこれには役立ちません。${parameter:-[word]}
${parameter%[word]}
${#parameter}
${parameter^^}
${parameter}
${10}
${11}
答え4
変数内のスペースとスペース|特殊文字を処理するには、必ず二重引用符で囲む必要があります。適切なIFSを設定するのも良い方法です。
尊敬される: http://www.dwheeler.com/essays/filenames-in-shell.html