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'
シェルスクリプトで一重引用符リテラルを使用して文字列を作成する場合は、一重引用符文字をで書く必要があります'\'''
。これはシェル構文に関する質問で、文字通り文字列を印刷するのとはまったく異なる質問です。
答え2
興味深い質問を見つけました...
問題は、POSIX互換性が不足していることですdash
。
POSIX 小規模組み込みシステムと Linux など、UNIX 互換性を必要とする大規模システムを区別するデフォルトの POSIX 互換性レベル。後者の場合、システムはいわゆるXSI拡張をすべて実装する必要があります。
XSI互換システムには、echo
拡張パラメータでいくつかのバックスラッシュエスケープが必要です。
bash
bash
POSIX / XSI準拠の動作でコンパイルすることは可能ですが(たとえば、SolarisやMacOSで実行されます)、Linuxのバイナリはこれを実行しません。 POSIX / XSI準拠のためにコンパイルされている場合、パラメータのバックスラッシュエスケープをbash
正しく処理し、サンプルコードエスケープシーケンスにPOSIX / XSIがないため、サンプルecho
コードはSolarisまたはMacOSの対応するバイナリに対して機能します。bash
XSIはLinuxと互換性がないため、bash
パラメータのバックラッシュエスケープをまったく拡張しません。これがサンプルコードがecho
Linuxでも機能する理由です。bash
dash
相手はPOSIX / XSI準拠を主張し、echo
パラメータのバックスラッシュエスケープを拡張します。 POSIX / XSI準拠が正しく実装されると、サンプルコードdash
も機能します。dash
これは、サンプルコードにPOSIX / XSIバックスラッシュエスケープシーケンスが含まれていないためです。
POSIX/XSI にはecho
拡張が必要です。
\0nnn for an octal number that represents the related character
サンプルコードにはバックスラッシュシーケンスが含まれています。
\1 for the first sed subexpression
そして
\2 for the second sed subexpression
echo
そしてこれはPOSIX / XSIエスケープシーケンスの一部ではないため、POSIX互換シェルの組み込み関数はそれを拡張できません。ただし、POSIXでは8進数が誤って拡張されるため、これを禁止します。これがサンプルコードが失敗して表示される理由です。echo
dash
\1
\2
dash
バグレポートを送信しdash
て修正されるecho arg
のをprintf '%s\n' arg
待つdash
か。printf
dash
したがって、POSIX / XSIエラーを一覧表示できますdash
。
マルチバイト文字はサポートされていません。
禁止されていてもパラメータ
\nnn
で拡張されます。echo
これが必要な場合でも、
\nnn
パラメータは拡張されません。printf