\0
コマンドラインで使用できますか?
背景
GNU Parallel のコーナーケースをテストするために、コマンドラインですべての文字が正しく引用符で囲まれているかどうかが気になりました。そのほとんどは次のとおりです。
perl -e 'print pack ("c*",1..255,10)' | parallel -k echo | md5sum
d03484ca75b3e38be411198d66bf4611 -
perl -e 'print pack ("c*",1..255,10)' | md5sum
d03484ca75b3e38be411198d66bf4611 -
しかし、\0
これは難しいようです (ここでは で示されていますA\0B\n
)。
perl -e 'print pack ("c*",65,0,66,10)' | wc -c
4 (A\0B\n)
perl -e 'print pack ("c*",65,0,66,10)' | parallel echo | wc -c
2 (A\n)
perl -e 'print pack ("c*",65,0,66,10)' | parallel --dry-run echo | wc -c
9 (echo A\0B\n)
perl -e 'print "echo ",pack ("c*",65,0,66,10)' | bash | wc -c
3 (AB\n)
2 番目の例については、ある程度正当化できます。 は\0
EOS として解釈される可能性がありますが、例 4 の場合も同様であるはずです。例 3 は、GNU Parallel が を\0
EOS として認識せず、 に渡すことを強調していますbash
。
何が起こっているのか説明していただけますか。特にケース 4 は私には理解できません。
そして更に重要なことに:
\0
例えば、コマンドラインで引用符を付けて、それを表示させる方法はありますかecho
?
答え1
コマンドを実行する場合、引数のリストは、execve()
システム コールに渡される NUL で終了する文字列へのポインターのリストです ( に渡される NUL で終了する文字列の別のリストである環境変数と同様ですexecve()
)。
その結果、処刑されたコマンドには NUL 文字を含めることはできません。
例外は、引数に何でも含めることができるシェル内の組み込み関数と関数ですzsh
(これらは組み込み関数なので、execve()
システム コールは関係ありません)。
NUL 文字を含むデータは、stdin (または他のファイル記述子) 経由で、または任意のタイプのファイルで渡すことができます。または、何らかの形式のエンコードを理解するコマンドもあります。
たとえば、UNIX 準拠のecho
実装では、\0
(2 つの文字のバックスラッシュとゼロ) が NUL 文字を意味すると理解されます。他の実装では、フラグが渡された場合にのみこれを実行します-e
。
それで:
echo '\0'
または:
echo -e '\0'
echo
NUL 文字の後に LF 文字が出力される可能性があります。
とzsh
、
echo $'\0'
NUL 文字をecho
組み込みに渡します。
/bin/echo $'\0'
動作しないの/bin/echo
は処刑されたしたがって、その引数には NUL 文字を含めることはできません。
質問のポイント 4 についてですが、bash はこれらの NUL 文字を無視するだけです。他のシェルでは動作が異なります。
$ printf 'e\0cho a\0b\n' | bash |& sed -n l
ab$
$ printf 'e\0cho a\0b\n' | ksh |& sed -n l
ksh: syntax error at line 1: `zero byte' unexpected$
$ printf 'e\0cho a\0b\n' | zsh |& sed -n l
zsh: command not found: e$
$ printf 'e\0cho a\0b\n' | rc |& sed -n l
line 1: warning: null character ignored$
line 1: warning: null character ignored$
ab$