Maj*_*imi 106 bash ksh quoting test
我对使用单括号或双括号感到困惑。看看这段代码:
dir="/home/mazimi/VirtualBox VMs"
if [[ -d ${dir} ]]; then
echo "yep"
fi
Run Code Online (Sandbox Code Playgroud)
尽管字符串包含空格,但它工作得很好。但是当我将其更改为单括号时:
dir="/home/mazimi/VirtualBox VMs"
if [ -d ${dir} ]; then
echo "yep"
fi
Run Code Online (Sandbox Code Playgroud)
它说:
./script.sh: line 5: [: /home/mazimi/VirtualBox: binary operator expected
Run Code Online (Sandbox Code Playgroud)
当我将其更改为:
dir="/home/mazimi/VirtualBox VMs"
if [ -d "${dir}" ]; then
echo "yep"
fi
Run Code Online (Sandbox Code Playgroud)
它工作正常。有人可以解释发生了什么吗?什么时候应该在变量周围分配双引号,"${var}"以防止空格引起的问题?
Sie*_*geX 104
单括号[实际上是test命令的别名,而不是语法。
单括号的(许多)缺点之一是,如果它尝试评估的一个或多个操作数返回空字符串,它会抱怨它期待两个操作数(二进制)。这就是为什么你看到人们这样做[ x$foo = x$blah ],x保证操作数永远不会评估为空字符串。
[[ ]]另一方面,双括号是语法并且比[ ]. 正如您所发现的,它没有“缺少操作数”的问题,而且它还允许使用更多类似 C 的>, <, >=, <=, !=, ==, &&, ||运算符语法。
我的建议如下:如果你的口译员是#!/bin/bash,那么总是使用[[ ]]
重要的是要注意,[[ ]]并非所有 POSIX shell 都支持它,但是许多 shell 确实支持它,例如zsh并且ksh除了bash
Gil*_*il' 62
该[命令是一个普通的命令。尽管大多数 shell 将其作为内置程序提供以提高效率,但它遵守 shell 的正常语法规则。[完全等同于test,除了[需要 a]作为它的最后一个参数,而test不是。
双括号[[ … ]]是特殊的语法。它们是在 ksh 中引入的(几年之后[),因为[正确使用可能很麻烦,并且[[允许一些使用 shell 特殊字符的新的很好的添加。例如,你可以写
[[ $x = foo && $y = bar ]]
Run Code Online (Sandbox Code Playgroud)
因为整个条件表达式是由shell解析,而[ $x = foo && $y = bar ]将第一被分成两个命令[ $x = foo和$y = bar ]由分离的&&操作者。类似地,双括号启用模式匹配语法之类的东西,例如[[ $x == a* ]]测试的值是否x以a;开头。在单括号中,这将扩展a*到名称以a当前目录开头的文件列表。双括号首先在 ksh 中引入,并且仅在 ksh、bash 和 zsh 中可用。
在单括号内,您需要在变量替换周围使用双引号,就像在大多数其他地方一样,因为它们只是命令(恰好是[命令)的参数。在双括号内,您不需要双引号,因为 shell 不进行分词或通配符:它解析的是条件表达式,而不是命令。
但是[[ $var1 = "$var2" ]],如果要进行字节到字节的字符串比较,则需要引号的地方是一个例外,否则$var2将是要匹配的模式$var1。
您不能做的一件事[[ … ]]是将变量用作运算符。例如,这是完全合法的(但很少有用):
if [ -n "$reverse_sort" ]; then op=-gt; else op=-lt; fi
…
if [ "$x" "$op" "$y" ]; then …
Run Code Online (Sandbox Code Playgroud)
在你的例子中
dir="/home/mazimi/VirtualBox VMs"
if [ -d ${dir} ]; then …
Run Code Online (Sandbox Code Playgroud)
内的命令if是[与所述4个参数-d,/home/mazimi/VirtualBox,VMs和]。shell 解析-d /home/mazimi/VirtualBox然后不知道如何处理VMs. 您需要防止分词${dir}以获得格式良好的命令。
一般来说,除非您知道要对结果执行分词和通配符,否则始终在变量和命令替换周围使用双引号。不使用双引号是安全的主要地方是:
foo=$bar但请注意,您确实需要export "foo=$bar"在数组赋值中或数组赋值中使用双引号array=("$a" "$b"));case声明:case $foo in …;=or==运算符的右侧除外(除非您确实需要模式匹配):[[ $x = "$y" ]].在所有这些中,使用双引号是正确的,因此您不妨跳过高级规则并一直使用引号。
什么时候应该在变量周围分配双引号,
"${var}"以防止空格引起的问题?
这个问题隐含的是
为什么不够好?
${variable_name}
${variable_name} 并不意味着你认为它的作用............如果你认为它有什么做所造成的空间问题(在变量值)。
对此有好处:${variable_name}
$ bar=foo
$ bard=Shakespeare
$ echo $bard
Shakespeare
$ echo ${bar}d
food
Run Code Online (Sandbox Code Playgroud)
没有别的!1 ?
没有任何好处,除非您紧跟在它后面的可能是变量名称一部分的字符:字母(-或-)、下划线()或数字(-)。即便如此,你也可以解决这个问题:${variable_name}AZaz_09
$ echo "$bar"d
food
Run Code Online (Sandbox Code Playgroud)
我并不是要阻止它的使用——
echo "${bar}d"这可能是这里最好的解决方案——而是阻止人们依赖大括号而不是引号,或者本能地应用大括号然后问,“现在,我还需要引号吗?”?
您应该始终使用引号,除非您有充分的理由不这样做,并且您确定自己知道自己在做什么。
_________________
1 ???当然,除了参数扩展的更高级形式,例如,
和
,建立在语法之上。此外,您需要使用,等来引用第 10 个、第 11 个等位置参数——引号不会帮助您解决这个问题。${parameter:-[word]}${parameter%[word]}${parameter}${10}${11}