目录是否不可写



谁能告诉我为什么这总是说目录不可写,而绝对是可写的?

   $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"

最新更新