正如其他人所说,$dnam 变量需要双引号。原因如下:
[ ... ] 是test 命令的别名。如果你查看你的系统,你会看到一个名为/bin/[ 或/bin/usr/[ 的文件。在某些系统上,这是指向/bin/test 或/bin/usr/test 的硬链接。 if 语句执行if 之后的内容,如果该命令返回零退出状态,if 语句将执行then 子句。否则,如果有 else 子句,则会改为执行。
为了进行布尔测试,Unix 包含了test 命令,所以你可以这样做:
if test -d "$directory"
then
echo "Directory $directory exists!"
fi
后来,/bin/[ 被添加为语法糖。这与上面的相同:
if [ -d "$directory" ]
then
echo "Directory $directory exists!"
fi
现在,[ 和 test 都是内置命令,但它们是 *still 命令。这意味着shell会插入命令然后执行它。
尝试执行以下操作:
$ set -xv # Turns on shell debugging
$ dnam="/home/bryan/renametest/C D"
dnam="/home/bryan/renametest/C D"
+ dnam='/home/bryan/renametest/C D'
$ test -d $dnam
test -d $dnam
+ test -d /home/bryan/renametest/C D
$ echo $?
echo $?
+ echo 1
1
$ test -d "$dnam" # Now with quotes
test -d $dnam
+ test -d "/home/bryan/renametest/C D"
$ echo $?
echo $?
+ echo 0
0
$ set +xv # Turn off the debuggin
每个命令都回显两次。第一次写入,第二次插入行后。作为插值的一部分,shell 在空白处分割参数。如您所见,test 命令正在测试/home/bryan/renamtest/C 的存在,它不存在因此不可写。我真的很惊讶 test 命令没有打印错误消息,因为您向它传递了一个额外的参数。
在第二次尝试中,您添加了引号。这些引号防止 shell 将您的参数拆分为空间并将目录名称保留为单个参数。
由于[ ... ]是一个命令,所以必须考虑到shell对变量的插值等问题。而且,如果您不是非常小心,最终可能会出现错误。
更糟糕的是,有时[ ... ] 可能有效,有时可能无效。如果您的目录名称不包含空格,它将按预期工作。想象一下,您正在编写一个程序,并且您对其进行测试并且一切正常,因为您尝试过的所有目录都没有空格。然后,有人使用您的程序,但在目录中有空间。 if 语句中的此类问题存在大量 shell 脚本错误。
这就是 Bash 引入 [[ ... ]] 测试的原因。 [[ 不是命令而是语句。这意味着外壳不会直接对结果进行插值。相反,参数被解析,然后进行任何插值。因此,这是可行的:
dnam="/home/bryan/renametest/C D" # No "$" in front of the variable!
# Is the directory writable
if [[ ! -w $dnam ]] # No quotation marks needed!
then
# Not writable. Pop the error and exit.
echo "Directory $dnam is not writable"
err=1
fi
使用[[ ... ]] 测试几乎总是比使用[ ... ] 测试更好,所以继续养成这个习惯吧。
还有一个小错误,你有:
$dnam="/home/bryan/renametest/C D"
这由 shell 插入,所以设置的变量是 $dnam 的值。如果$dnam 恰好等于“foo”,你会这样做:
foo="/home/bryan/renametest/C D"
不是你想要的。
您想在设置变量时关闭$:
dnam="/home/bryan/renametest/C D"