2016-07-14 51 views
1

我之前在終端上玩過,發現我可以通過製作單字命令('ls','cat','python2.7','exit')與命令命名相同的文件或目錄。然而,我不能執行'多字'命令('rm \ -rf *','ls -a','python2.7 \ test.py')(這也導致我發現你不能刪除名爲'-rf'的目錄和'rm -rf *')除非參數是按字母順序排列的。表面上看,當你傳入*到bash時,它會按照字母順序讀取文件/目錄的名稱,並將每個連續的名稱作爲參數傳遞給前一個命令。例如:Bash:使用文件名作爲通配符的命令

$ mkdir cat 
$ touch dog 
$ vim dog # at this point I put 'Hello!' into dog 
$ * 
Hello! 

爲什麼通配符不允許我帶空格執行文件的命令,但允許我執行多個文件名的命令?謝謝!

編輯:也別名不工作的原因。例如:

$ alias lsa='ls -a' 
$ mkdir lsa 
$ * 
No command 'lsa' found, did you mean: 
    ... 
lsa: command not found 

任何人都知道這是爲什麼?

+0

不知道這個的目的是什麼,只是不建議創建名爲「sudo」的文件。 – pmod

+0

我只是覺得它很整潔,想知道一些關於它背後的機制的更多細節。不知道爲什麼它被啓用。 –

+0

也許「strace *」將有助於理解... – pmod

回答

2

每個命令bash進程都受到幾種擴展,然後bash將解釋並處理結果。其中最後一個是路徑名擴展,其中bash檢查命令的單詞(由以前的擴展和單詞分割產生),其中包含任何未引號的特殊字符*,?[,並將這些單詞解釋爲模式表示文件名稱。所有擴展完成後,擴展命令中的所有重定向和變量賦值都將執行並從命令中刪除。如果剩下任何單詞,則首先將其作爲要運行的命令的名稱。這個詞的出處並不重要。

在路徑名擴展中,*匹配任何字符串,包括空字符串。當bash對僅包含*的單詞執行路徑名擴展時,它將擴展爲工作目錄中所有文件的名稱,但以點(.)開頭的文件除外。

因此,如果您的工作目錄包含一個名爲ls只是一個單一的文件,並執行命令*,bash的擴展了命令ls並執行它,產生輸出ls。同樣,如果目錄的內容是echo,Hello,World!,那麼當您執行命令*時,bash會將其展開爲等效於echo Hello, 'World!',並且命令輸出爲Hello, World!

這並不像你認爲的那樣適用於帶空格的文件名,因爲每個匹配模式的文件名都被擴展爲一個單詞。這些不會隨後分裂。 (Bash確實在擴展過程中執行了「分詞」操作,但在路徑名擴展之前會發生)。這通常是您想要的,否則諸如rm *之類的命令不會可靠地按照您的預期進行操作。

這不適用於別名,因爲bash讀取命令時擴展了別名,而不是在執行它們時。這有幾個含義,但其中之一是在執行任何擴展之前解釋別名。另一個是別名的替換文本受制於所有正常的擴展。