評価する

評価する
$ FILE="$(mktemp)"
$ printf "a\0\n" > "$FILE"
$ od -tx1z "$FILE"
0000000 61 00 0a                                         >a..<
0000003

今まではそんなに良くなった。

上記の内容をbashスクリプトでカプセル化しました。

#! /bin/bash

cmd=("$@")
FILE="$(mktemp)"
eval "${cmd[@]}" > "$FILE"
od -tx1z "$FILE"

しかし、

$ script printf 'a\0\n' 
0000000 61 30 6e                                         >a0n<
0000003

出力が\0リテラル文字列になるのはなぜですか?これが起こらないようにするにはどうすればよいですか?


この投稿ではあまり重要ではありません。私の問題は、いくつかのコマンドをbashスクリプトでラップしようとした結果です。NUL 除去によるコマンド拡張の防止:

FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"

答え1

出力が\0リテラル文字列になるのはなぜですか?これが起こらないようにするにはどうすればよいですか?

.evalバックスラッシュでエスケープされた 0 と 0 を使用してevalコマンドを実行し、バックスラッシュを削除してそのままにします。printf a\0\nn

代わりに、これを効果的に防ぐことができますeval。を使用すると、"$@" > "$FILE" スクリプト引数で指定されたコマンドを実行できる必要があります。ただし、この場合は使用できませんeval。あるいは、コマンドを引数として渡す必要がないように全体を再設計することもできます。

コマンド拡張がNULを削除するのを防ぐために、いくつかのコマンドをbashスクリプトでラップしようとしています。

S="$(uuencode -m "$FILE" /dev/stdout)"

これはここで問題ですか?uuencode -mNULバイトを生成してはいけません。バイナリデータをテキストにエンコードするので正反対です。

最後のスクリプトはa、NUL および改行文字を作成して に渡します。これにより、16進表現または同様の内容が$FILE印刷されます。od0000000 61 00 0a

答え2

NULをstdout、stderrとして出力するか、stdinから受け取ることができます。
何でも「内部」捕獲そして(ほぼ)NULを使うと問題になります。

stdoutにNULを発行できます。

$ printf 'a\0b' | sed -n l
a\000b$

または:

$ printf 'a\0b' | cat -A
a^@b

ファイルもあります:

$ printf 'a\0b' >outfile

そして正確にこれはスクリプトにも当てはまります。

評価する

最初のスクリプトの問題は、次を使用していることですeval

$ cmd=(printf 'a\0b\n')
$ echo "${cmd[@]}"
printf a\0b\n

$ eval echo "${cmd[@]}"
printf a0bn

2番目のループでは、バックスラッシュを解析するシェル行が削除されます。
体験版を使用しないでください。

$ "${cmd[@]}"| sed -n l
a\000b$

拡大する

これはprintf、組み込みタスクとstdoutNUL操作の両方が可能であることを証明します。

しかし、これは失敗します。

$ printf '%s\n' "$(printf 'a\0b')" | cat -A
bash: warning: command substitution: ignored null byte in input
ab$

(bash 4.4+では)警告メッセージもあります。

つまり、シェル(ほとんどのシェル)は内部的にC文字列を使用し、C文字列は最初のNULで終了します。一部のシェルは、「コマンド拡張」の最初のNULで切り捨てられます。

$ ksh -c 'echo $(printf "a\0b\n")|sed -n l'    # also yash
a$

一部はNULを削除しました。

$ bash -c 'echo $(printf "a\0b\n")|sed -n l'
ab$

一部はNULを空白に変更することもあります。

$ zsh -c 'echo $(printf "a\0b\n")|sed -n l'
a b$

変数の割り当てでも同様の問題が発生します。

コーディング

はい、リンクされた回答はuuencodeファイルの内容をエンコード(およびデコード)します。

より簡単なアプローチは次のとおりですxxd(8進ダンプを元に戻すことができます)。

FILE="$(mktemp)"
printf "a\0b\n" > "$FILE"
S=$(xxd -p "$FILE")
xxd -r -p <(printf '%s' "$S") | xxd -p
rm "$FILE"

関連情報