2017-08-12 53 views
3

几天前,我的实验室的服务器遭受了严重的崩溃,当我们的一名实习生意外复制粘贴此代码bash试图删除node.js.大括号内扩展导致奇怪的行为

$ rm -rfv /usr/{bin/node,lib/node,share/man /*/node.*}; 

他们尝试了brace expansion列出了目录中删除,但是目录分隔符(/)之间的通知空间。这最终删除了我们服务器上的所有内容,因为它们应用了sudo。 我在我的虚拟机上试过这个命令,并确认它与rm -rf /非常相当。

我对bash解释陈述的方式感到困惑。当我尝试创建一个简单的,非破坏性的命令来做类似的事情时(空间起分隔符的作用来扩展),我似乎无法解决这个问题。我尝试的第一个命令,而是for循环在bash:

$ for f in /usr/{bin/node,lib/node,share/man /*/node.*}; do echo $f; done 

其列在node.js中的目录部分内容/。这应该证实这不是rm中的特殊功能。

但是当我尝试这样的事:

$ for f in {a,b c,d e}; echo $f 

它导致近echo语法错误,我希望A到E,每次在一行字母。

我做了一些研究,但找不到解释这种行为的任何事情。 有人能告诉我,在第一个命令中,bash是如何解释这个命令的?


p.s.我发现在zsh'for循环测试'版本不起作用。尽管如此,从未尝试过真正的'rm测试'。我很害怕。

回答

4

您必须\ -escape所有的空间,是你的大括号展开的一部分:

$ printf '%s\n' {a,b\ c} 
a 
b c 

括号扩展唯一的工作:

  • 时,他们既没有既不单也不双引号(你有那部分权利)

  • 时,他们承认为壳一个字(标记)(这就是你的尝试逊于) - 因此需要字符个人\引用的空间。

没有这一点,bash中断你的意思是一个括号扩展到多个参数,括号扩展从未发生过 - 见下文。


至于如何bash解析/usr/{bin/node,lib/node,share/man /*/node.*}: 下面告诉你所得到的参数(省略以便更好地说明发生了什么实际的通配):

$1=/usr/{bin/node,lib 
$2=/ 
$3=node,share 
$4=/ 
$5=man 
$6=/* 
$7=/ 
$8=node.*} 

正如你可以看到:

  • 未转义的空格会导致空格出现分词,从而将您要表达的表达式分解为多个参数。

  • 一个所得到的参数/*的,不幸的是,相匹配的目录中的所有(非隐藏)项,并因此传递给sudo rm时肆虐。