Работа с двоичными данными на низком уровне в сценариях оболочки, как правило, плохая идея.
bashпеременные не могут содержать байт 0. zshэто единственная оболочка, которая может хранить этот байт в своих переменных.
В любом случае аргументы команды и переменные окружения не могут содержать эти байты, поскольку они являются строками с разделителями NUL, передаваемыми execveсистемному вызову.
Также обратите внимание, что:
var=`cmd`
или его современная форма:
var=$(cmd)
удаляет все завершающие символы новой строки из вывода cmd. Таким образом, если этот двоичный вывод заканчивается в 0xa байтах, он будет искажен при сохранении в $var.
Здесь вам нужно хранить закодированные данные, например, с помощью xxd -p.
hdr_988=$(head -c 988 < "$inputFile" | xxd -p)
printf '%s\n' "$hdr_988" | xxd -p -r > "$output_hdr"
Вы можете определить вспомогательные функции, такие как:
encode() {
eval "$1"='$(
shift
"$@" | xxd -p -c 0x7fffffff
exit "${PIPESTATUS[0]}")'
}
decode() {
printf %s "$1" | xxd -p -r
}
encode var cat /bin/ls &&
decode "$var" | cmp - /bin/ls && echo OK
xxd -pвывод не занимает мало места, так как он кодирует 1 байт в 2 байта, но он облегчает манипуляции с ним (конкатенация, извлечение частей). base64это тот, который кодирует 3 байта в 4, но с ним не так легко работать.
ksh93Оболочка имеет встроенную команду формат кодирования (использование base64) , которые вы можете использовать свои readи printf/ printкоммунальные услуги:
typeset -b var # marked as "binary"/"base64-encoded"
IFS= read -rn 988 var < input
printf %B var > output
Теперь, если нет транзита через переменные оболочки или env или аргументы команды, вы должны быть в порядке, пока используемые вами утилиты могут обрабатывать любое значение байта. Но обратите внимание, что для текстовых утилит большинство реализаций, не относящихся к GNU, не могут обрабатывать байты NUL, и вы захотите зафиксировать локаль в C, чтобы избежать проблем с многобайтовыми символами. Последний символ, не являющийся символом новой строки, также может вызвать проблемы, а также очень длинные строки (последовательности байтов между двумя байтами 0xa, которые длиннее LINE_MAX).
head -cгде он доступен, здесь должно быть все в порядке, так как он предназначен для работы с байтами и не имеет смысла рассматривать данные как текст. Так
head -c 988 < input > output
должно быть хорошо. На практике, по крайней мере, встроенные реализации GNU, FreeBSD и ksh93 в порядке. POSIX не указывает -cопцию, но говорит, что headдолжен поддерживать строки любой длины (не ограничиваясь LINE_MAX)
С zsh:
IFS= read -rk988 -u0 var < input &&
print -rn -- $var > output
Или:
var=$(head -c 988 < input && echo .) && var=${var%.}
print -rn -- $var > output
Даже zshесли, если он $varсодержит NUL-байты, вы можете передать его как аргумент zshвстроенным (как printописано выше) или функциям, но не как аргументы исполняемым файлам, поскольку аргументы, передаваемые исполняемым файлам, являются строками с разделителями NUL, это ограничение ядра, независимое от оболочки.
ddдля копирования отдельных байтов (установив егоcountв1). Я не уверен насчет их хранения.