2017-08-12 52 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時肆虐。