谁能告诉我为什么总是说目录不可写,而绝对是不可写的?
$dnam="/home/bryan/renametest/CD" # 目录是否可写 错误=0 如果 [ !-w $dnam] 然后 # 不可写。弹出错误并退出。 echo "目录 $dnam 不可写" 错误=1 菲
你需要双引号$dnam
- 没有它们,它会被解释为两个单独的 shell 单词,“/home/bryan/renametest/C”和“D”,这会产生无效的测试表达式并因此失败。这应该有效:
if [ ! -w "$dnam" ]
@tink 的建议[[ ]]
是进行此类测试的一种更简洁的方法,但仅适用于 bash(以及其他一些具有扩展语法的 shell)。您得到的事实[[: not found
意味着您使用的是相当基本的 shell,而不是 bash。
我看到多个问题:
您在变量中使用了一个空格。这不是非法的,但在组合行中,您使用变量 unscaped 并生成以下命令:
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
在某些系统上,这是指向or的硬链接/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对变量的插值等问题。而且,如果您不是非常小心,最终可能会出现错误。
更糟糕的是,有时[ ... ]
可能会起作用,有时可能不起作用。如果您的目录名称不包含空格,它将按预期工作。想象一下,您正在编写一个程序,并且您对其进行测试并且一切正常,因为您尝试过的所有目录都没有空格。然后,有人使用您的程序,但在目录中有空间。大量的 shell 脚本错误是针对if
语句中的此类问题。
这就是 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"