Bashは変数に16進値0x00を格納できません。

Bashは変数に16進値0x00を格納できません。

ddでいくつかのトリックを試しています。私は "header"という変数に16進値を格納してddにパイプすることができると思いました。

変数のない最初のステップは次のとおりです。

$ echo -ne "\x36\xc9\xda\x00\xb4" |dd of=hex
$ hd hex

00000000  36 c9 da 00 b4                                    |6....|
00000005

その後、私はこれを試しました:

$ header=$(echo -ne "\x36\xc9\xda\x00\xb4") 
$ echo -n $header | hd

00000000  36 c9 da b4                                       |6...|
00000004

ご覧のとおり、変数の\x00値を失いました$header。この行動の説明がある人はいますか?これが私を狂わせます。

答え1

Bash は終端のためにヌルバイトを予約する C スタイル文字列を使用するので、文字列にヌルバイトを格納することはできません。したがって、 Bash が途中で保存する必要なく、null バイトを含むシーケンスを単純にパイプするようにスクリプトを再構築する必要があります。たとえば、次のようにできます。

printf "\x36\xc9\xda\x00\xb4" | hd

ところで、他の多くの簡単なタスクにはechoBashを使用できます。printf

あるいは、リンクの代わりに一時ファイルを使用することもできます。

printf "\x36\xc9\xda\x00\xb4" > /tmp/mysequence
hd /tmp/mysequence

もちろん、ファイルが/tmp/mysequenceすでに存在する可能性があるという問題があります。これで一時ファイルを作成し、そのパスを文字列として保存する必要があります。

または、プロセス置換を使用してこれを回避できます。

hd <(printf "\x36\xc9\xda\x00\xb4")

演算子は、最初の引数として受け取る<(command)ファイルシステムに名前付きパイプを生成します。パイプを開いて読みます。commandhdほぼ他のファイルと同じです。ここで詳細を読むことができます。https://unix.stackexchange.com/a/17117/136742

答え2

zsh変数にNUL文字を格納できる唯一のシェルを使用できます。文字は$IFSinのデフォルト値にある場合もありますzsh

nul=$'\0'

または:

nul=$'\x0'

または

nul=$'\u0000'

または

nul=$(printf '\0')

ただし、引数や環境変数などの変数は、次のコマンドに渡すことはできません。処刑された引数と環境変数は、execve()システムコールに渡されるNULで区切られた文字列であるためです(シェルではなくシステムAPIの制限)。ただし、zshNULバイトを関数または組み込みコマンドの引数として渡すことができます。

echo $'\0' # works
/bin/echo $'\0' # doesn't

答え3

Bash は内部的に C 文字列を使用し、ヌルバイトを格納できません。次のように一時ファイルに値を保存します。

    zHex=$(mktemp --tmpdir "$(basename "$0")-XXXX")
    trap "rm -f ${zHex@Q}" EXIT

変数zHexには一意のファイル名が含まれます。 $zHexが参照するファイルは手動で削除できますが、何らかの理由でプログラムが終了すると自動的に削除されます。

次に、変数を次のように使用します。

    echo -ne "\x36\xc9\xda\x00\xb4" > "$zHex"
    hd "$zHex"

nullバイトの値は変数に格納されません。代わりに変数を使用してファイル名を保存します。他のファイルと同様に、このファイルにはNULLバイトを含めることができ、引き続き使用できます。ファイル自体は物理的にディスクに書き込まれない可能性があります。

トラップを使用すると、bashは自動的にファイルを削除するため、クレイジーなゴミ配列を作成しない限り、手動で削除することを心配する必要はありません。この技術はRAMバッファリングのため非常に高速です。

答え4

キャリッジリターンはファイル名の一部である可能性があるため、nullで終わるリストを使用するのが好きです。ただし、Bashは文字列を単純なC文字列として格納します。ここで、NULLバイトは文字列終端子であるため、文字列自体の一部にすることはできないため、bashにはNULLバイトの文字列を格納できません。

この問題を解決するために、各要素の後にヌルバイトがあると仮定する文字列配列を作成しました。リスト自体には明らかにヌルバイトが含まれています。 nullバイトを含む値をこのように配列として格納します。

    readarray -d $'\0' zArray < <(null_terminated_list_maker)

これにより、次のようにnullバイトを使用して値を再現できます。

    [[ "${zArray[*]}" ]] && printf '%s\0' "${zArray[@]}"

このように bash 配列を使用して、null バイトを含むすべての値を格納できます。

目的[[ "${zArray[*]}" ]]は、配列に値があることを確認することです(空の文字列は値です)。このテストは、空の配列をprintfに渡すと、printfが誤ったnullバイトを印刷する問題を解決します。何も印刷しないでください。

完全にランダムなデータを表現するには、次の質問があります。入力は実際にはnullバイトで終わりますか?ヌルバイトで終了または終了できない可能性があるデータを処理するには、このメソッドを拡張する必要があります。

関連情報