1

1

だから私は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進文字列を使用できます。

hexdump16進数に変換するには、、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を含むファイルを作成できます。headtail

$ 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« \0NUL()で終わる文字列»。この例は、CPOSIXのいくつかの例を含むいくつかのライブラリとツールでコーディングされています。良い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'ゼロ値を含めることができます。

関連情報