Работа с двоичными данными на низком уровне в сценариях оболочки, как правило, плохая идея.
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
). Я не уверен насчет их хранения.