2008-09-19 96 views
97

例如。如何在bash中轉義通配符/星號字符?

me$ FOO="BAR * BAR" 
me$ echo $FOO 
BAR file1 file2 file3 file4 BAR 

,並使用 「\」 轉義符:

me$ FOO="BAR \* BAR" 
me$ echo $FOO 
BAR \* BAR 

我明明做一些愚蠢的事。

如何獲得輸出「BAR * BAR」?

回答

96

設置$ FOO時引用是不夠的。你需要引用變量的引用,以及:

me$ FOO="BAR * BAR" 
me$ echo "$FOO" 
BAR * BAR 
+0

這很神祕,這是爲什麼?到底是怎麼回事? – tofutim 2018-03-10 22:38:07

3
FOO='BAR * BAR' 
echo "$FOO" 
+0

這工作,而是要改變在第一線,雙引號單引號它不是必需的。 – finnw 2008-09-19 14:08:51

+1

不,這不是,但是當你要包含特殊的外殼字符並且你不想要任何替換時,使用單引號的習慣更可取。 – tzot 2008-09-19 14:10:37

3
echo "$FOO" 
3

這可能是值得進入命令行上使用printf而不是echo的習慣。

在這個例子中,它沒有多少好處,但它對於更復雜的輸出可能更有用。

FOO="BAR * BAR" 
printf %s "$FOO" 
+0

爲什麼在地獄中? printf是一個單獨的進程(至少不是內置的bash),並且使用printf對回顯沒有任何好處。 – ddaa 2008-09-19 14:35:18

+1

printf *是*一個內置的bash,我在我的答案中說過「在這個例子中,它並沒有帶來太多好處,但它對於更復雜的輸出可能更有用。」 – 2008-10-02 10:50:22

73

簡短的回答

像其他人說的 - 你應該總是引用變量,以防止奇怪的行爲。所以使用echo「$ foo」而不是僅僅echo $ foo

長的答案

我認爲這個例子值得進一步解釋,因爲有更多的事情比它可能會在它的臉上似乎。

我能看到你的困惑來自於你跑,你可能會想到自己的第一個例子是,外殼顯然做,因爲後:

  1. 參數擴展
  2. 文件名擴展

所以從你的第一個例子:

me$ FOO="BAR * BAR" 
me$ echo $FOO 

A壓腳提升參數擴展相當於:

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擴展的完整說明,請參閱:

http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions

37

我會有點添加到這個古老的線程。

通常你會使用

$ echo "$FOO" 

不過,我有問題,即使有這樣的語法。考慮下面的腳本。

#!/bin/bash 
curl_opts="-s --noproxy * -O" 
curl $curl_opts "$1" 

*需要被逐字傳遞給curl,但也會出現同樣的問題。上面的例子將不起作用(它將擴展到當前目錄中的文件名)並且都不會\*。您也不能引用$curl_opts,因爲它將被識別爲curl的單一(無效)選項。

curl: option -s --noproxy * -O: is unknown 
curl: try 'curl --help' or 'curl --manual' for more information 

因此,我建議使用bash可變$GLOBIGNORE的乾脆防止文件名擴展如果施加到全局模式,或使用set -f內置標誌。

#!/bin/bash 
GLOBIGNORE="*" 
curl_opts="-s --noproxy * -O" 
curl $curl_opts "$1" ## no filename expansion 

應用到你原來的例子:

me$ FOO="BAR * BAR" 

me$ echo $FOO 
BAR file1 file2 file3 file4 BAR 

me$ set -f 
me$ echo $FOO 
BAR * BAR 

me$ set +f 
me$ GLOBIGNORE=* 
me$ echo $FOO 
BAR * BAR