当变量为空或未设置时,为什么 [ -d $dirname ] 会匹配?为什么这会导致主目录的内容被删除?

当变量为空或未设置时,为什么 [ -d $dirname ] 会匹配?为什么这会导致主目录的内容被删除?

好吧,我有这个代码

dirname=

if [ -d $dirname ];
 then
 cd $dirname && rm *
fi

正如你所看到的,我有这个空变量,我想知道为什么当使用像这样带有单方括号的空变量时,它会删除所有用户的主目录文件

如果我使用双方括号,它不会删除用户的主目录文件

像这样

dirname=

if [[ -d $dirname ]];
 then
 cd $dirname && rm *
fi

我已经阅读了使用单方括号和双方括号时的差异语法

我可以知道为什么会发生这种情况吗?

答案1

cd不传递参数时,它将更改为默认目录(大多数情况下是用户的主目录$HOME)。

这个问题有趣的部分是,当您不向-dbashtest[内置操作符传递任何内容时,bash 似乎会以 0 退出(在我看来,这是意外的)。

当您设置dirname为空变量时,您实际上是在运行以下命令:

if [ -d ]; then
    cd && rm *
fi

对我来说,令人惊讶的是该块内的代码if被执行,但我可以在我的机器上确认它确实如此。正如上面的注释所解释的,test不再将 解释-d为运算符,而只是返回 0,因为它是一个非空字符串。帮助防止这种行为的一种方法是确保引用变量:

if [ -d "$dirname" ]; then
    cd "$dirname" && rm *
fi

在这种情况下,如果$dirname为空,您将传递""-d正确计算非零退出代码的运算符,因此块内的代码不会被执行。

答案2

未引用的内容$dirname会受到分词的影响,如果它是空的,它就会被分割已删除,在 和 中[ -d $dirname ]cd $dirname只留下[ -d ]cd

在第一个中,[仅看到一个参数(在[和之间]),在这种情况下,测试是查看该参数是否为非空字符串。-d是,所以测试为真。 (这类似于[ -z $var ]测试是否$var为空的方式,但[ -n $var ]根本不起作用。)

至于cd,普通文件cd将更改为用户的主目录,因此这就是rm *发生的地方。


使用 时[[ .. ]],不会发生分词,因为它[[是一个特殊的 shell 结构,[与常规命令不同。

解决办法是对变量扩展加双引号,出于各种原因,在大多数情况下您都会想要这样做。就像这样:

if [ -d "$dirname" ]; then
    cd -- "$dirname" && rm ./*
fi

看:

相关内容