Использование двоичных данных в качестве параметра в bash – любой способ разрешить nuls?

Поэтому я хотел бы передать первые 512 байт файла binaryFile.dd в качестве второго параметра для myProgram, но bash удаляет все символы NUL. Есть ли способ избежать этого в bash, или я нахожусь в никуда?

myProgram parameter1 "$(head -c 512 binaryFile.dd)" 

3 Solutions collect form web for “Использование двоичных данных в качестве параметра в bash – любой способ разрешить nuls?”

Невозможно передать нулевой байт в параметр команды. Это не из-за ограничения bash, хотя bash также имеет это ограничение. Это ограничение интерфейса для запуска команды: он обрабатывает нулевой байт как конец параметра. Механизма выхода нет.

Большинство оболочек не поддерживают нулевые байты в переменных или в аргументах функций и встроенных функций. Заметным исключением является 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, если вы попытаетесь передать параметр внешней команде, то все, что следует за нулевым байтом, игнорируется – не zsh, а ядром.

 $ zsh -c 'a=$(printf foo\\0bar); /usr/bin/printf "$a"' | od -t x1 0000000 66 6f 6f 0000003 

Если вы хотите передать null байты в программу, вам нужно найти какой-то способ, отличный от параметра командной строки.

 head -c 512 binaryFile.dd | myProgram --read-parameter2-from-stdin parameter1 myProgram --read-parameter2-from-file=<(head -c 512 binaryFile.dd) parameter1 

bash не подходит для обработки двоичных данных напрямую.

Либо используйте двоичные данные с файлом, либо используйте шестнадцатеричную строку, представляющую ваши данные.

Для преобразования в шестнадцатеричном виде вы можете использовать hexdump , xxd , od .

Например, чтобы преобразовать 512 байтов в шестнадцатеричную строку, используйте

 xxd -ps -c 512 file.bin 

Чтобы преобразовать его в двоичное использование

 echo "$myhexstring" | xxd -r -ps > file.bin 

Нет, нет способа, чтобы строка в bash могла содержать NUL ( \0 ).
Поэтому переменная (так как она содержит строку) не может содержать NUL.

Причина в том, что bash написан с парадигмой c «строка заканчивается в NUL». [1] Ядро linux также налагает такое ограничение. [2] Но даже если ядро ​​должно было позволить NULs в строках [3] (аргументы), большинство оболочек и, в частности, bash, не могли включать NUL внутри переменных [4] .

Позиционные параметры ( $1 , $2 и т. Д.) Эквивалентны переменным и также не могут содержать NUL.

Однако nuls может существовать в файлах, потоках и в printf:

 $ printf 'test\0nuls\n' | od -vAn -tx1c 74 65 73 74 00 6e 75 6c 73 0a test \0 nuls \n 

Как вы можете видеть, printf создает NUL и течет через трубу ( | ). Но NULs чередуются с «командами»:

 $ 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 testnuls \n 

В bash 4.4 он даже выдает предупреждение. zsh в этом случае, молча заменить NULs пробелом:

 $ zsh -c ' echo $(printf "test\0nuls\n") | od -vAn -tx1c' 74 65 73 74 20 6e 75 6c 73 0a testnuls \n 

Мы можем создать файл, содержащий NULs с printf, и часть файла cat , head , tail или dd, которая содержит NUL:

 $ 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] способа иметь содержимое двоичного файла в качестве аргумента. Возможно, шестнадцатеричное представление может работать:

 $ myProgram "$parameter1" "$(xxd -ps -c 512 binaryFile.dd)" 

Спасибо @Gilles за всю дополнительную работу (и подробную информацию) ниже.

1

[1] Все сводится к старому определению C string что «строки заканчиваются в NUL ( \0 )». Эта парадигма была закодирована в нескольких библиотеках и инструментах C , из которых POSIX имеет несколько примеров. Как strcpy здесь, что состояния (выделение мое):

Функция strcpy () должна скопировать строку, на которую указывает s2 ( включая завершающий символ NUL ), в массив, на который указывает s1.

Это означает, что предполагается, что строка прекращается с помощью NUL.
Или, другими словами, может быть только один NUL, последний.

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 included \0 null 

Невозможно использовать NUL в аргументах, переданных вызовом execve() :

 $ zsh -c 'a=$(printf "included\0null"); /usr/bin/printf "$a"' | od -vAn -tx1c 69 6e 63 6c 75 64 65 64 included 

3

[3] Но даже если ядро, в котором можно включить NULs в аргументы, 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 includednull 

В 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 included \0 null $ printf 'included\0null' | ( read a; printf '%s\n' "$a" | od -vAn -tx1c ) 69 6e 63 6c 75 64 65 64 6e 75 6c 6c includednull 

Если запущенная оболочка zsh, то (вместо этого) будет работать с нулем:

 $ 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 included \0 null \n 

5

[5] Значение, что «прямое» (простое) включение байта значения 0 ( \0 ) невозможно. Но закодированный (сложный), либо используя C-строку $'\0' , в шестнадцатеричном, базовом 64, или какой-то эквивалент, можно включить значение нуля.

Interesting Posts
Linux и Unix - лучшая ОС в мире.