2011-02-13 55 views
4

我發現了這一點,在試圖鞏固我的腳本字符串安全:這是GNU Bash中的一個錯誤嗎?

$ echo '!!' 
!! 
$ echo "$(echo '!!')" 
echo "$(echo 'echo '!!'')"  #<~ the console echoes the line with expanded history here 
echo !!       #<~ the result 

在我看來,最裏面的報價,這是單引號,應該擴大什麼,可變的,子shell或其他,但在這種情況下,它將!!擴展到最後一行類型。似乎不應該那樣做。

我問你:這是一個Bash中的錯誤,並且如果可以使用一個帶引號的子shell擴展輸出感嘆號?

(在Linux中使用bash 4.1.007)

編輯:

如果上面的是不是一個錯誤,爲什麼,那麼,這是否像預期的那樣?

$ foo='some value' 
$ echo "$(echo 'neither $foo nor `this subshell` should expand here')" 
neither $foo nor `this subshell` should expand here 
+1

不是一個錯誤。這是bash如何擴展論證。有人會參考手冊的相關部分回答。 – Juliano 2011-02-13 16:44:35

回答

2

我同意。

$ echo "$(echo '!!')" 
echo "$(echo 'echo $(echo '!!')')" 
echo $(echo !!) 

應該做同樣的

$ echo $(echo '!!') 
!! 

我看不出怎麼解釋基礎上,history expansion documentation的差異。

歷史擴展文檔如何與shell expansions documentation的其餘部分完全分開,這也很奇怪。

zsh回聲!!兩者,至少與我的設置。

1

這可能是一個錯誤,但set +H將禁用(這是默認關閉的腳本反正)。

下面是從該名男子頁的相關章節:

雙引號引起的字符保留的 字面值引號內的所有字符,$,`,\例外,而且, 當啓用歷史擴展時,!字符$和`保留 它們在雙引號內的特殊含義。反斜槓保留其 特殊含義,只有在後跟以下字符之一時纔有效: $,`,「,\或<換行>。雙引號可以在雙引號內加上反斜槓。 ,歷史擴展 將除非立即執行進行!出現在雙引號是使用反斜線 。之前的反斜槓!不會被刪除。

歷史擴展在完成一行之後是 ,在shell將其分解爲單詞之前。 ...歷史擴張是由 介紹的歷史擴張字符的出現,這是!通過 默認。只有反斜槓(\)和單引號可以引用歷史記錄 擴展字符。

+0

「用雙引號括起字符......」 - 就是這樣。劉海單引號。如果它是那裏的一個變量,它*不會擴展。 – amphetamachine 2011-02-13 22:40:18

+0

@amphetamachine除了單引號(通常)在雙引號之間發生時(正如他們在這種情況下所做的那樣)會失去其特殊含義。 `$()`確實賦予了單引號的特殊含義,但顯然bash並沒有在歷史擴展之前解析它。從某種意義上說,它*不應該解析它,因爲歷史替換可能包含像$(`和```這樣可能會改變它周圍事物的引用狀態的東西... – 2011-02-14 04:04:12

1

如果你把兩個劉海變成一個變量,你會得到你期望的結果(以及更多的字符串安全性)。

(
#set -xv 
twobangs='!!' 
echo "${twobangs}" 
echo "$(echo "${twobangs}")" 
echo "$(echo 'echo "${twobangs}"')" 
echo "$(echo "echo "${twobangs}"")" 
echo "$(echo "echo ""${twobangs}")" 
#set -xv 
) 

與此類似,有時可以使用shell的內置字符串連接,只是把一個字符,如「!」轉換成單引號來防止shell的解釋。

(
set -H 
echo "Hello, world"'!' 
(sleep 10) & 
#trap "echo exit; kill -TERM $!" EXIT HUP INT QUIT TERM # troublemaker 
#trap "echo exit; kill -TERM $"'!' EXIT HUP INT QUIT TERM 
trap "echo exit; kill -TERM $"'!'"; echo killed" EXIT HUP INT QUIT TERM 
sleep 5 
)