簡短的回答
像其他人所說的那樣 - 你應該總是引用變量來防止奇怪的行為。所以使用echo“$ foo”代替echo $ foo。
長期回答
我確實認為這個例子值得進一步解釋,因為它的表面看起來比它看起來更多。
我可以看到你的困惑在哪里,因為在你運行你的第一個例子后,你可能會認為shell顯然正在做:參數擴展
文件名擴展
所以從你的第一個例子:me$?FOO="BAR?*?BAR"me$?echo?$FOO
參數擴展后相當于:me$?echo?BAR?*?BAR
文件名擴展后相當于:me$?echo?BAR?file1?file2?file3?file4?BAR
如果只輸入echo BAR * BAR命令行,您將看到它們是等效的。
所以你可能會想到“如果我逃避*,我可以阻止文件名擴展”
所以從你的第二個例子:me$?FOO="BAR?\*?BAR"me$?echo?$FOO
參數擴展后應相當于:me$?echo?BAR?\*?BAR
文件名擴展后應相當于:me$?echo?BAR?\*?BAR
如果您嘗試直接在命令行中鍵入“echo BAR \ * BAR”,它將確實打印“BAR * BAR”,因為轉義會阻止文件名擴展。
那么為什么使用$ foo不起作用?
這是因為發生了第三次擴張 - 報價清除。從bash手冊中刪除引用是:在前面的擴展之后,所有未引用的字符“\”,“”和“”的出現都將被刪除,這些字符不是由上述擴展之一產生的。
所以當你直接在命令行輸入命令時,轉義字符不是先前擴展的結果,所以BASH在將它發送到echo命令之前將其刪除,但在第二個例子中,“\ *”是先前參數擴展的結果,因此不會被刪除。結果,echo收到“\ *”,這就是它打印的內容。
請注意第一個示例之間的差異 - “*”不包括在將被刪除的字符中刪除的字符中。
我希望這是有道理的。最后得出的結論 - 只是使用引號。我只是想我會解釋為什么轉義,如果只有參數和文件名擴展在起作用,它在邏輯上應該起作用,不起作用。
有關BASH擴展的完整說明,請參閱: