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
工作正常。有人可以解释发生了什么吗?何时应在诸如
"${var}"
之类的变量周围分配双引号以防止空格引起的问题? #1 楼
单括号[
实际上是test
命令的别名,它不是语法。单括号(很多)的缺点之一是,如果它试图评估的一个或多个操作数返回一个空字符串,它将抱怨它期望两个操作数(二进制)。这就是为什么人们看到
[ x$foo = x$blah ]
的原因,而x
则保证了操作数绝不会为空字符串。另一方面,双括号
[[ ]]
是语法,并且比[ ]
更强大。如您所见,它不存在“缺少操作数”的问题,并且还允许>, <, >=, <=, !=, ==, &&, ||
运算符使用更多类似C的语法。我的建议如下:如果您的解释器是
#!/bin/bash
,则始终使用[[ ]]
请注意,并非所有POSIX外壳程序都支持
[[ ]]
,但是除zsh
之外,许多外壳程序都支持ksh
和bash
评论
空字符串(以及许多其他问题)通过使用引号解决。 “ x”是另一种问题:其中操作数可以用作运算符。就像$ foo是!或(或-n ...这个问题并不意味着POSIX shell的问题([和]旁边)不大于4。
–StéphaneChazelas
2013年1月25日20:36
为了澄清,[x $ foo = x $ blah]与[$ foo = $ bar]一样错误。 [“ $ foo” =“ $ bar”]在任何符合POSIX的shell中都是正确的,[“ x $ foo” =“ x $ bar”]在任何类似Bourne的shell中都可以使用,但是x不适用于您有空字符串,但是$ foo可能在哪里!或-n ...
–StéphaneChazelas
2013年3月7日16:29
这个答案中有趣的语义。我不确定您的意思是* not *语法。当然,[并不是测试的确切别名。如果是这样,则测试将接受一个封闭的方括号。测试-n foo]。但是测试没有,并且[需要一个。 [在所有其他方面都与test相同,但这不是别名的工作原理。 Bash将[和测试描述为shell内置函数,但是[[描述为shell关键字。
– kojiro
17-10-9在13:02
好吧,在bash中[是内置的shell,但/ usr / bin / [也是可执行文件。传统上,它是/ usr / bin / test的链接,但在现代gnu中,coreutils是单独的二进制文件。传统版本的测试会检查argv [0],以查看是否将其作为[调用,然后寻找匹配的]。
–埃文
19年1月9日在20:03
我的bash不适用于> =和<=
–学生
19年7月22日在13:15
#2 楼
[
命令是普通命令。尽管大多数外壳程序将其作为效率的内置组件提供,但它遵循外壳程序的常规语法规则。 [
与test
完全等效,不同之处在于[
要求]
作为最后一个参数,而test
不需要。双括号
[[ … ]]
是特殊语法。它们是在ksh中([
之后的数年)引入的,因为[
可能难以正确使用,并且[[
允许添加一些使用shell特殊字符的新功能。例如,您可以编写[[ $x = foo && $y = bar ]]
,因为整个条件表达式都是由Shell解析的,而
[ $x = foo && $y = bar ]
首先会分成两个命令[ $x = foo
和$y = bar ]
,并由&&
分隔操作员。类似地,双括号使诸如模式匹配语法之类的东西成为可能。 [[ $x == a* ]]
测试x
的值是否以a
开头;在单括号中,这会将a*
扩展到当前目录中名称以a
开头的文件列表。双括号最早是在ksh中引入的,仅在ksh,bash和zsh中可用。在单括号内,您需要像在其他大多数地方一样在变量替换周围使用双引号,因为它们是只是命令的参数(恰好是
[
命令)。在双括号内,您不需要双引号,因为外壳程序不进行单词拆分或加修饰:它解析的是条件表达式,而不是命令。[[ $var1 = "$var2" ]]
是一个例外如果要进行字节对字符串的比较,则用引号引起来,否则,$var2
将成为匹配$var1
的模式。[[ … ]]
不能做的一件事是使用变量作为操作员。例如,这是完全合法的(但很少使用):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 …
if
内部的命令是[
,带有4个参数-d
,/home/mazimi/VirtualBox
,VMs
和]
。 Shell解析-d /home/mazimi/VirtualBox
,然后不知道如何处理VMs
。为了获得格式正确的命令,您需要防止在${dir}
上进行单词拆分。通常来说,除非您知道要在菜单上执行单词拆分和globing,否则始终在变量和命令替换周围使用双引号。结果。安全使用双引号的主要地方是:
在赋值中:
foo=$bar
(但请注意,在export "foo=$bar"
或数组赋值(例如array=("$a" "$b")
中)确实需要双引号) ; 在
case
语句中:case $foo in …
; 在双括号内,但
=
或==
运算符的右侧除外(除非您想要模式匹配):[[ $x = "$y" ]]
。在所有这些中,使用双引号是正确的,因此您最好跳过高级规则并始终使用引号。
评论
@StephaneChazelas我的一个错误。事实证明,[确实来自1981年的System III,我认为它更旧。
–吉尔斯'所以-不再是邪恶的'
13年7月7日在15:13
#3 楼
我什么时候应该在
"${var}"
之类的变量周围加上双引号,以防止空格引起的问题?这个问题的隐含意义是
为什么
${variable_name}
不够好? ${variable_name}
并不意味着您认为它会做什么... ...如果您认为它与空格引起的问题有关(以可变值表示) 。
${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
我并不想阻止其使用-
echo "${bar}d"
可能是这里最好的解决方案— 但是要劝阻人们不要使用大括号而不是引号,或者本能地使用大括号然后问,
“现在,我需要还有引号吗?”
除非有充分的理由不要使用引号,否则
并且您确定自己知道自己在做什么。
_________________1当然,
例如,
${parameter:-[word]}
和${parameter%[word]}
的更高级形式的参数扩展基于${parameter}
语法。 此外,您还需要使用
,
等,引用第10、11等位置参数-
引用将无济于事。 >
#4 楼
为了处理变量中的空格和空格|特殊字符,您应始终在其周围加上双引号。设置适当的IFS也是一种好习惯。
推荐:
http://www.dwheeler.com/essays/filenames-in-shell.html
评论
Bash常见问题解答31一个更通用的vs问题:unix.stackexchange.com/questions/306111/…