sh
以下のスクリプトを実行すると、使用されているシェルが次のかどうかに応じて2つの異なる出力が表示されます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モードで実行したときに何が起こるかを知りたいです。
編集:ボーナスポイントの場合、echo
関数内で交換したときにBashでもこれが起こる理由を説明してください。printf
regex
printf 's/\(.* \)\(!\{0,1\}\)has(/\1\2MOCK_has(/g'
ベストアンサー1
説明はにあります。POSIX仕様echo
:
標準出力に書き込まれる文字列。最初のオペランドがある
-n
場合、またはオペランドに<backslash>文字が含まれている場合、結果は実装に従って定義されます。
POSIXは主に歴史的慣行を性文化し、時には歴史的慣行は一貫していません。一部のシェルは、引数のエスケープシーケンスをたとえばタブとecho
バイト\t
値\1
が1()の文字に展開します^A
。他のシェルはバックスラッシュをプレーン文字として扱います。
ランダムな文字列を印刷する移植可能な方法は、常に最初の引数(形式)でバックスラッシュエスケープシーケンスを拡張することを使用することですprintf
。printf
文字列を文字通り印刷するには、次のようにします。
printf %s 's/\(.* \)\(!\{0,1\}\)has(/\1\2MOCK_has(/g'
文字列を文字通り印刷し、末尾に改行文字を追加するには、次のようにします。
printf '%s\n' 's/\(.* \)\(!\{0,1\}\)has(/\1\2MOCK_has(/g'
シェルスクリプトで一重引用符リテラルを使用して文字列を作成する場合は、一重引用符文字をで書く必要があります'\'''
。これはシェル構文に関する質問で、文字通り文字列を印刷するのとはまったく異なる質問です。