Bash
/bin/sh 計算字元串,而 Bash 不計算
執行下面的腳本時,我得到兩個不同的輸出,具體取決於使用的 shell 是
sh
還是bash
:regex(){ echo 's/\(.* \)\(!\{0,1\}\)has(/\1\2MOCK_has(/g' } replace_builtins(){ sed -e "$(regex)" } echo 'if !has(\"nvim\"): ' | replace_builtins
- 重擊:
if !MOCK_has(\"nvim\"):
- 噓:
??MOCK_has(\"nvim\"):
(這些問號最初是從終端逐字複製的,但在我保存文章時消失了。它本質上是不可列印的字元)
我想知道在解釋這種現象的 POSIX sh 模式下執行時發生了什麼。
編輯:為了獎勵積分,請解釋為什麼在 Bash 中替換函式
echo
時也會發生這種情況:printf``regex
printf 's/\(.* \)\(!\{0,1\}\)has(/\1\2MOCK_has(/g'
解釋在POSIX 規範中
echo
:要寫入標準輸出的字元串。如果第一個操作數是
-n
,或者任何操作數包含 <backslash> 字元,則結果是實現定義的。POSIX 主要編纂歷史實踐,有時歷史實踐並不一致。一些 shell 將參數中的轉義序列擴展為
echo
,例如\t
擴展為製表符並\1
擴展為字節值為 1 (^A
) 的字元。其他 shell 將反斜杠視為普通字元。列印任意字元串的可移植方式是使用
printf
.printf
總是在其第一個參數(格式)中擴展反斜杠轉義序列。要按字面意思列印字元串,請使用printf %s 's/\(.* \)\(!\{0,1\}\)has(/\1\2MOCK_has(/g'
要逐字列印字元串並在末尾添加換行符,請使用
printf '%s\n' 's/\(.* \)\(!\{0,1\}\)has(/\1\2MOCK_has(/g'
請注意,如果在 shell 腳本中使用單引號文字編寫字元串,則需要將單引號字元寫為
'\'''
. 這是關於 shell 語法的,這是一個與字面列印字元串完全不同的問題。