谁能告诉我为什么这总是说目录不可写,而绝对是可写的?
$dnam="/home/bryan/renametest/C D" # 目录可写吗 错误=0 如果 [ ! -w $dnam ] 然后 # 不可写。弹出错误并退出。 echo "目录$dnam不可写" 错误=1 fi
在$dnam
两边加上双引号 - 没有它们,它被解释为两个单独的shell单词"/home/bryan/renametest/C"和"D",这会产生无效的测试表达式,因此失败。这应该有效:
if [ ! -w "$dnam" ]
@tink 对 [[ ]]
的建议是一种更简洁的测试方式,但仅在 bash(以及其他一些具有扩展语法的 shell(中可用。你得到[[: not found
的事实意味着你使用的是相当基本的shell,而不是bash。
我看到多个问题:
-
您在变量中使用空格。这并不违法,但在组合行中,您使用变量 unescape 并生成以下命令:
if [ ! -w /home/bryan/renametest/C D ]
这不是有效的语法。解决此问题的最简单方法是将行更改为
if [ ! -w "$dnam" ]
-
下一个问题更糟:在我的系统上,
help test
返回文本:-w FILE True if the file is writable by you.
这意味着,该命令不支持目录,而仅支持文件。如果要检查目录是否可写,则必须使用其他命令
正如其他人所说,$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
都是内置命令,但它们仍然是命令。这意味着 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
每个命令都会回显两次。第一次是写入的,第二次是行后插值。作为插值的一部分,外壳在空白处拆分参数。如您所见,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"