Bash

/bin/sh 計算字元串,而 Bash 不計算

  • February 26, 2021

執行下面的腳本時,我得到兩個不同的輸出,具體取決於使用的​​ 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 語法的,這是一個與字面列印字元串完全不同的問題。

引用自:https://unix.stackexchange.com/questions/636245