だから私はbinaryFile.ddの最初の512バイトをmyProgramの2番目の引数として渡したいのですが、bashはすべてのNUL文字を削除します。 Bashでこれを避ける方法はありますか、それともすべてを隠していますか?
myProgram parameter1 "$(head -c 512 binaryFile.dd)"
答え1
コマンドパラメータにNULLバイトを渡すことはできません。 bashにもこれらの制限がありますが、これはbashの制限によるものではありません。これはコマンドを実行するインターフェイスの制限です。 null バイトを引数の末尾として扱います。脱出メカニズムはありません。
ほとんどのシェルは、関数と組み込み関数の変数または引数でNULLバイトをサポートしていません。 Zshは注目すべき例外です。
$ ksh -c 'a=$(printf foo\\0bar); printf "$a"' | od -t x1
0000000 66 6f 6f
0000003
$ bash -c 'a=$(printf foo\\0bar); printf "$a"' | od -t x1
0000000 66 6f 6f 62 61 72
0000006
$ zsh -c 'a=$(printf foo\\0bar); printf "$a"' | od -t x1
0000000 66 6f 6f 00 62 61 72
0000007
ただし、zshを使用してもパラメーターを外部コマンドに渡そうとすると、nullバイト以降のすべての内容はzshではなくカーネルでは無視されます。
$ zsh -c 'a=$(printf foo\\0bar); /usr/bin/printf "$a"' | od -t x1
0000000 66 6f 6f
0000003
プログラムにヌルバイトを渡すには、コマンドライン引数以外の方法を見つける必要があります。
head -c 512 binaryFile.dd | myProgram --read-parameter2-from-stdin parameter1
myProgram --read-parameter2-from-file=<(head -c 512 binaryFile.dd) parameter1
答え2
bash
バイナリデータを直接処理するのには適していません。
ファイルにバイナリデータを使用するか、データを表す16進文字列を使用できます。
hexdump
16進数に変換するには、、xxd
を使用できますod
。
たとえば、512バイトを16進文字列に変換するには、次のようにします。
xxd -ps -c 512 file.bin
次のようにしてバイナリに戻します。
echo "$myhexstring" | xxd -r -ps > file.bin
答え3
いいえ、Bashの文字列にはNUL()を含めることはできません\0
。
したがって、変数(文字列を含む)にはNULを含めることはできません。
c
その理由は、bashが「文字列はNULで終了します」パラダイムで書かれているからです。[1] Linuxカーネルもこれらの制限を適用します。[2]ただし、カーネルが文字列[3] (パラメータ) で NUL を許可しても、ほとんどのシェル、特に bash は変数[4]に NUL を含めることはできません。
位置パラメータ($1
など$2
)は変数と同じで、NULを含めることはできません。
ただし、ファイル、ストリーム、およびprintfにはnulが存在する可能性があります。
$ printf 'test\0nuls\n' | od -vAn -tx1c
74 65 73 74 00 6e 75 6c 73 0a
t e s t \0 n u l s \n
ご覧のとおり、printfはNULを生成し、パイプ(|
)を通って流れます。ただし、NULは「コマンド実行」から削除されます。
$ echo $(printf 'test\0nuls\n') | od -vAn -tx1c
bash: warning: command substitution: ignored null byte in input
74 65 73 74 6e 75 6c 73 0a
t e s t n u l s \n
Bash 4.4では警告も表示されます。この場合、zsh は自動的に NUL を空白に置き換えます。
$ zsh -c ' echo $(printf "test\0nuls\n") | od -vAn -tx1c'
74 65 73 74 20 6e 75 6c 73 0a
t e s t n u l s \n
printfとNULを含むファイルの一部またはddcat
を使用して、NULを含むファイルを作成できます。head
tail
$ printf 'test\0nuls\0in\0files\0\n' > testnul.bin
$ cat testnul.bin | xxd -ps
74657374006e756c7300696e0066696c6573000a
$ head -c 7 testnul.bin | xxd -ps
74657374006e75
$ dd if=testnul.bin bs=7 count=1 | xxd -ps
74657374006e75
1+0 records in
1+0 records out
7 bytes copied, 0.000655689 s, 10.7 kB/s
$ dd if=testnul.bin bs=7 count=1 2>/dev/null| xxd -ps
74657374006e75
あなたの場合、バイナリファイルの内容をパラメータとして使用する簡単な[5]方法はありません。おそらく16進表現が機能します:
$ myProgram "$parameter1" "$(xxd -ps -c 512 binaryFile.dd)"
すべての追加作業(および詳細)について@Gillesに感謝します。
1
[1]
すべては昔に帰結する定義C string
« \0
NUL()で終わる文字列»。この例は、C
POSIXのいくつかの例を含むいくつかのライブラリとツールでコーディングされています。良いstrcpy
ここにあります。それは次のように言います(強調)。
strcpy()関数はs2が指す文字列をコピーする必要があります(終了 NUL 文字を含む)をs1が指す配列に入れます。
これは、文字列がNULで終わると仮定することを意味します。
つまり、最後のNULが1つしかない可能性があります。
2
[2]システムexecve()
コール、POSIXでも定義、文字列(コマンドパラメータ)がNULで終了すると予想されます。これがNULでシェルを使用できる理由です(ほとんどは使用できませんが、zshは注目に値する例外です)。
$ zsh -c 'a=$(printf "included\0null"); printf "$a"' | od -vAn -tx1c
69 6e 63 6c 75 64 65 64 00 6e 75 6c 6c
i n c l u d e d \0 n u l l
できるいいえ呼び出しに渡されたパラメータにNULを使用してくださいexecve()
。
$ zsh -c 'a=$(printf "included\0null"); /usr/bin/printf "$a"' | od -vAn -tx1c
69 6e 63 6c 75 64 65 64
i n c l u d e d
サム
[3]ただし、カーネルが引数に NUL を含めることができても、 bash はこれを許可しません。
$ bash -c 'a=$(printf "included\0null"); /usr/bin/printf "$a"' | od -vAn -tx1c
bash: warning: command substitution: ignored null byte in input
69 6e 63 6c 75 64 65 64 6e 75 6c 6c
i n c l u d e d n u l l
Bash 4.4では、NULが削除されると警告も表示されます。
4
[4] ほとんどのシェル、特にbashは変数にNULを含めることはできません。
$ printf 'included\0null' | od -vAn -tx1c
69 6e 63 6c 75 64 65 64 00 6e 75 6c 6c
i n c l u d e d \0 n u l l
$ printf 'included\0null' | ( read a; printf '%s\n' "$a" | od -vAn -tx1c )
69 6e 63 6c 75 64 65 64 6e 75 6c 6c
i n c l u d e d n u l l
実行中のシェルがzshの場合は、代わりにnullが使用されます。
$ zsh -c 'printf "included\0null" | ( read a; printf "%s\n" "$a" | od -vAn -tx1c )'
69 6e 63 6c 75 64 65 64 00 6e 75 6c 6c 0a
i n c l u d e d \0 n u l l \n
5
[5]これは、値が0()のバイトを「直接」(単純に)含む\0
ことが不可能であることを意味します。ただし、16進数、64進数、または同等の形式のC文字列エンコード(複素数)を使用すると、$'\0'
ゼロ値を含めることができます。