我試圖理解爲什麼猛砸刪除雙引號(而不是單引號),這樣做的變量擴展與${parameter:+word}
(使用替代值)時,一個在這裏的文檔中,例如:
% var=1
% cat <<EOF
> ${var:+"Hi there"}
> ${var:+'Bye'}
> EOF
Hi there
'Bye'
根據在手冊中,:+
之後的「單詞」通過代字符擴展,參數擴展,命令替換和算術擴展進行處理。這些都不應該做任何事情。
我缺少什麼?如何在擴展中獲得雙引號?
我試圖理解爲什麼猛砸刪除雙引號(而不是單引號),這樣做的變量擴展與${parameter:+word}
(使用替代值)時,一個在這裏的文檔中,例如:
% var=1
% cat <<EOF
> ${var:+"Hi there"}
> ${var:+'Bye'}
> EOF
Hi there
'Bye'
根據在手冊中,:+
之後的「單詞」通過代字符擴展,參數擴展,命令替換和算術擴展進行處理。這些都不應該做任何事情。
我缺少什麼?如何在擴展中獲得雙引號?
這種行爲看起來是故意的 - 它在我嘗試的所有Bourne shell中是一致的(例如,ksh93和zsh的行爲方式相同)。
這種行爲相當於將這裏的doc視爲雙引號,對於這些特殊的擴展只有。換句話說,你得到
$ echo "${var:+"hi there"}"
hi there
$ echo "${var:+'Bye'}"
'Bye'
相同的結果只有在POSIX規範我發現一些特別的東西發生在參數擴展雙引號的話非常微弱的暗示。這是從informative "Examples" section of Parameter Expansion:
模式的雙引號是不同的,這取決於放置雙引號的位置。
"${x#*}"
<星號>是一個模式字符。
${x#"*"}
字面<星號>被引用而不是特殊的。
我會讀取最後一行作爲暗示,報價清除雙引號適用於該詞。這個例子對於單引號是沒有意義的,並且通過省略,對於單引號沒有引號刪除。
更新
我試圖在FreeBSD /bin/sh
,這是從一個Almquist殼牌的。這個shell輸出單引號和雙引號。所以全部炮彈的行爲不再一致,只有我試過的炮彈最多炮彈。
至於:+
後獲得雙引號的字的擴大,我的看法是
$ var=1
$ q='"'
$ cat <<EOF
${var:+${q}hi there$q}
EOF
"hi there"
$ cat <<EOF
${var:+bare alt value is string already}
${var:+'and these are quotes within string'}
${var:+"these are double quotes within string"}
${var:+"which are removed during substitution"}
"${var:+but you can simply not substitute them away ;)}"
EOF
bare alt value is string already
'and these are quotes within string'
these are double quotes within string
which are removed during substitution
"but you can simply not substitute them away ;)"
注意,是不需要在這裏文檔重現此:
$ echo "${var:+'foo'}"
'foo'
tl; dr
$ var=1; cat <<EOF
"${var:+Hi there}"
${var:+$(printf %s '"Hi there"')}
EOF
"Hi there"
"Hi there"
在替代值中包含雙引號的兩個實用解決方法。
嵌入式$(...)
方法比較麻煩,但更靈活:它允許包含嵌入式雙引號,並且還可以控制是否應該擴展該值。
Jens's helpful answer和Patryk Obara's helpful answer都闡明瞭進一步說明此問題。
注意,問題行爲同樣適用於:
定期雙引號字符串(如其他答案說明)(例如,echo "${var:+"Hi there"}"
;爲第1解決方法,你會必須\
-quote圍繞"
實例;例如,echo "\"${var:+Hi there}\""
;好奇地,因爲Gunstick指出在一個問題的評論,使用\"
在替代值產生"
輸出確實工作在雙引號字符串 - 例如,echo "${var:+\"Hi th\"ere\"}"
- 不像在不帶引號這裏-文檔)
相關的擴展${var+...}
,${var-...}
/${var:-...}
,並${var=...}
/${var:=...}
此外,還有一個相對於\
-處理相關的奇怪內部雙引號字符串/雙引號字符串內的雙引號替代值here-doc:bash
和ksh
意外地刪除嵌入\
實例;例如,
echo "${nosuch:-"a\b"}"
意外地產生了ab
,即使echo "a\b"
在分離產量爲a\b
-見this question。
我的行爲沒有解釋[1] ,但我可以提供務實的解決方案,與所有主要的POSIX兼容的外殼(dash
,bash
,ksh
,zsh
)工作:
請注意"
實例從不需要句法替代值內的原因:替代值爲含蓄對待像雙引號字符串:沒有代字號擴展,沒有分詞,並且沒有發生匹配,但參數擴展,算術擴展和命令替換都是執行。
注意,在涉及替代或前綴/後綴去除,參數擴展報價做有語法意義;例如:echo "${BASH#*"bin"}"
或echo "${BASH#*'bin'}"
- 奇怪的是,dash
不支持單引號。
如果你想用引號括的整個替代價值,它有沒有嵌入報價,你想它擴大,
引用整個擴張 ,它繞開"
從替代值中刪除的問題:
# Double quotes
$ var=1; cat <<EOF
"${var:+The closest * is far from $HOME}"
EOF
"The closest * is far from /Users/jdoe"
# Single quotes - but note that the alternative value is STILL EXPANDED,
# because of the overall context of the unquoted here-doc.
var=1; cat <<EOF
'${var:+The closest * is far from $HOME}'
EOF
'The closest * is far from /Users/jdoe'
對於嵌入式引號,或者防止替代值的膨脹,
使用嵌入式命令替換(未引用的,儘管它會表現得好像它被引用):
# Expanded value with embedded quotes.
var=1; cat <<EOF
${var:+$(printf %s "We got 3\" of snow at $HOME")}
EOF
We got 3" of snow at /Users/jdoe
# Literal value with embedded quotes.
var=1; cat <<EOF
${var:+$(printf %s 'We got 3" of snow at $HOME')}
EOF
We got 3" of snow at $HOME
這兩種方法可以根據需要進行組合。
[1] 實際上,替代值:
'
情況下,如在常規的雙引號字符串,被視爲文字。鑑於上述情況,
這將是有意義的治療嵌入式"
實例作爲文字太多,並且簡單地傳遞他們通過,就像'
實例。
相反,可悲的是,他們是去除,如果你試圖逃離他們作爲\"
的\
保留太(內加引號這裏的文檔,但奇怪的不是雙引號字符串內),除了在ksh
- 值得稱讚的例外 -,其中\
實例是刪除。在zsh
,奇怪的是,欲以\"
斷擴張完全(如做不平衡轉義的人在所有的炮彈)。
"
實例在不\"
內部-escaping它們(其中,如上所述,是無用的,因爲\
實例被保留)。鑑於隱式雙引號串的語義,文字$
實例必須是\$
轉義,或一個命令替換必須用於嵌入單個引號字符串($(printf %s '...')
)。
我覺得嵌入式'「'被視爲文字,然後刪除離開時,bash的價值進行評估。但是,讓我好奇,爲什麼前綴/後綴去除不行爲一致。我想我會需要尋找到bash的源代碼解開,真正發生的事情...... –
@PatrykObara:正是這種不一致性:雙引號在替代值中沒有語法_function_,但它們被_parsed就好像它們一樣__:引用移除被應用,正如你所描述的那樣,並且你不能在內部沒有'''' - 轉義它們(這是沒用的,因爲'\'被保留)。 – mklement0
@PatrykObara:這種差異可能是意想不到的,但在前綴/後綴刪除和字符串替換的引用中,_does_提供了一個有用的功能:區分模式元字符(例如'*')和文字(例如'「*」' ),所以我不會稱之爲不一致。 – mklement0
似乎是一個錯誤或執行泄漏。這是不可能用雙引號作爲備用值,而無需將其分配給一個變量:'DQ = '「'; ... $ {VAR:+ $ DQ}' – choroba
@choroba:'$ {VAR:+ $(回波'''')}'但我基本同意。也有一些是在word'的'解析很奇怪的報價參數擴展(在這裏參數擴展文檔展開彷彿報價,根據手冊,這似乎是這樣。) – rici
的這裏幾乎等價的文檔可以被看作是一個回聲「...」,在這種情況下,只需在命令提示符處輸入'echo「$ {var:+」Hi there「}」'就可以將其刪除。 \「但HERE文檔不一致,併產生」在輸出而不是「。有些東西顯然不正確。 – Gunstick