bash 目录是否不可写

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15780214/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 05:05:39  来源:igfitidea点击:

Is the directory NOT writable

linuxbashshelltestingwritable

提问by user2021539

Can anyone tell me why this is always saying that the directory is not writable, when it absolutely is?

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

    $dnam="/home/bryan/renametest/C D"

    # Is the directory writable
    err=0
    if [ ! -w $dnam ]
    then
        # Not writable. Pop the error and exit.
        echo "Directory $dnam is not writable"
        err=1
    fi

回答by Gordon Davisson

You need double-quotes around $dnam-- without them, it's interpreted as two separate shell words, "/home/bryan/renametest/C" and "D", which makes an invalid test expression and hence fails. This should work:

你需要双引号$dnam- 没有它们,它被解释为两个单独的 shell 词,“/home/bryan/renametest/C”和“D”,这会产生无效的测试表达式,因此失败。这应该有效:

if [ ! -w "$dnam" ]

@tink's suggestion of [[ ]]is a cleaner way of doing tests like this, but is only available in bash (and some other shells with extended syntax). The fact that you get [[: not foundmeans you're using a fairly basic shell, not bash.

@tink 的建议[[ ]]是进行此类测试的更简洁方法,但仅适用于 bash(以及其他一些具有扩展语法的 shell)。您得到的事实[[: not found意味着您使用的是相当基本的 shell,而不是 bash。

回答by Daniel Alder

I see multiple problems:

我看到多个问题:

  • You are using a space inside your variable. This is not illegal, but in combination line you use the variable unescaped and generate the following command:

    if [ ! -w /home/bryan/renametest/C D ]
    

    This is not a valid syntax. The simplest way to fix this is changing the line to

    if [ ! -w "$dnam" ]
    
  • The next problem is worse: On my system, help testreturns the text:

    -w FILE        True if the file is writable by you.
    

    Which means, the command doesn't support directories but only files. If you want to check if a directory is writable, you will have to use a different command

  • 您在变量中使用了一个空格。这不是非法的,但在组合行中您使用未转义的变量并生成以下命令:

    if [ ! -w /home/bryan/renametest/C D ]
    

    这不是有效的语法。解决此问题的最简单方法是将行更改为

    if [ ! -w "$dnam" ]
    
  • 下一个问题更糟:在我的系统上,help test返回文本:

    -w FILE        True if the file is writable by you.
    

    这意味着,该命令不支持目录,而只支持文件。如果要检查目录是否可写,则必须使用不同的命令

回答by David W.

As everyone else said, the $dnamvariable needs double quotes. Here's why:

正如其他人所说,$dnam变量需要双引号。原因如下:

The [ ... ]is an alias to the testcommand. If you look in your system, you will see a file called /bin/[or maybe /bin/usr/[. On some systems, this is a hard link to /bin/testor /bin/usr/test. The ifstatement executeswhat comes after the if, and if that command returns a zero exit status, the ifstatement will execute the thenclause. Otherwise, if there is an elseclause, that will execute instead.

[ ... ]是别名的test命令。如果你查看你的系统,你会看到一个名为/bin/[或者可能是/bin/usr/[. 在某些系统上,这是指向/bin/test或的硬链接/bin/usr/test。该if语句执行之后的内容if,如果该命令返回零退出状态,该if语句将执行该then子句。否则,如果有一个else子句,它将改为执行。

To allow for boolean testing, Unix included the testcommand, so you could do this:

为了允许布尔测试,Unix 包含该test命令,因此您可以执行以下操作:

if test -d "$directory"
then
    echo "Directory $directory exists!"
fi

Later on, the /bin/[was added as syntactic sugar. This is identical to the above:

后来,/bin/[被添加为语法糖。这与上面的相同:

if [ -d "$directory" ]
then
    echo "Directory $directory exists!"
fi

Now, both [and testare builtin commands, but they are *stillcommands. This means that the shell interpolates the command and then executes it.

现在,[test都是内置命令,但它们是*still命令。这意味着 shell 会插入命令,然后执行它。

Try executing the following:

尝试执行以下操作:

$ 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

Each command is echoed twice. The first time as written, and the second time after the line is interpolated. As part of the interpolation, the shell splits parameters on white space. As you can see, the testcommand is testing the presence of /home/bryan/renamtest/Cwhich doesn't exist and thus not writable. I'm actually surprised that the testcommand didn't print an error message because you passed it an extra parameter.

每个命令被回显两次。第一次写入,第二次插入行后。作为插值的一部分,shell 在空白处拆分参数。如您所见,该test命令正在测试/home/bryan/renamtest/C哪个不存在,因此不可写。我实际上很惊讶该test命令没有打印错误消息,因为您向它传递了一个额外的参数。

In the second attempt, you added quotes. These quotes prevented the shell from splitting your parameters on the space and keep the directory name as a single parameter.

在第二次尝试中,您添加了引号。这些引号防止 shell 在空间上拆分您的参数并将目录名称保留为单个参数。

Since [ ... ]is a command, you have to take into account the shell's interpolation of variables and other issues. And, if you're not absolutely careful, you can end up with errors.

既然[ ... ]是命令,你就必须考虑到 shell 的变量插值等问题。而且,如果您不十分小心,最终可能会出错。

Even worse, sometimes the [ ... ]might work and sometimes it might not. If your directory name didn't contain spaces, it will work as expected. Imagine you're writing a program, and you test it and everything works because all directories you've tried don't have spaces. Then, someone uses your program, but has a space in the directory. A substantial number of shell script bugs are do to this type of issue in ifstatements.

更糟糕的是,有时[ ... ]可能有效,有时可能无效。如果您的目录名称不包含空格,它将按预期工作。想象一下,您正在编写一个程序,并对其进行测试并且一切正常,因为您尝试过的所有目录都没有空格。然后,有人使用您的程序,但在目录中有一个空格。大量的 shell 脚本错误是针对if语句中的此类问题造成的。

This is why Bash introduced the [[ ... ]]tests. The [[isn't a command but a statement. This means that the shell doesn't directly interpolate the results. Instead, the parameters are parsed, and then any interpolation is done. Thus, this would have worked:

这就是 Bash 引入[[ ... ]]测试的原因。该[[不是命令而是一个声明。这意味着 shell 不会直接插入结果。相反,解析参数,然后完成任何插值。因此,这将起作用:

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

It's almost always better to use the [[ ... ]]test rather than the [ ... ]test, so go ahead and get into the habit.

使用[[ ... ]]测试几乎总是比[ ... ]测试更好,所以继续并养成习惯。

One more minor error, you had:

还有一个小错误,你有:

$dnam="/home/bryan/renametest/C D"

This gets interpolated by the shell, so the variable being set is whatever the value of $dnamjust happens to be. If $dnamhappened to equal "foo", you would been doing this:

这由 shell 进行插值,因此设置的变量是$dnam恰好是的值。如果$dnam碰巧等于“foo”,你会这样做:

foo="/home/bryan/renametest/C D"

Not what you want.

不是你想要的。

You want to leave the $off when you set variables:

您想$在设置变量时关闭:

dnam="/home/bryan/renametest/C D"