Я амбициозно пытаюсь перевести код C ++ в Bash по множеству причин.
Этот код читает и манипулирует типом файла, специфичным для моего подполя, который написан и полностью структурирован в двоичном виде. Моя первая задача, связанная с двоичными файлами, - скопировать первые 988 байт заголовка, в том виде, в каком они есть, и поместить их в выходной файл, в который я смогу продолжить запись по мере генерирования остальной информации.
Я почти уверен, что мое текущее решение не работает, и реально я не нашел хорошего способа определить это. Так что, даже если это действительно написано правильно, мне нужно знать, как я проверю это, чтобы быть уверенным!
Вот чем я сейчас занимаюсь:
hdr_988=`head -c 988 ${inputFile}`
echo -n "${hdr_988}" > ${output_hdr}
headInput=`head -c 988 ${inputTrack} | hexdump`
headOutput=`head -c 988 ${output_hdr} | hexdump`
if [ "${headInput}" != "${headOutput}" ]; then echo "output header was not written properly. exiting. please troubleshoot."; exit 1; fi
Если я использую hexdump / xxd для проверки этой части файла, хотя я не могу точно прочитать большую ее часть, что-то кажется неправильным. И код, который я написал для сравнения, говорит только, если две строки идентичны, а не если они скопированы так, как я хочу.
Есть ли лучший способ сделать это в Bash? Могу ли я просто скопировать / прочитать двоичные байты в native-binary, чтобы дословно скопировать в файл? (и в идеале хранить как переменные).
dd
для копирования отдельных байтов (установив егоcount
в1
). Я не уверен насчет их хранения.Ответы:
Работа с двоичными данными на низком уровне в сценариях оболочки, как правило, плохая идея.
bash
переменные не могут содержать байт 0.zsh
это единственная оболочка, которая может хранить этот байт в своих переменных.В любом случае аргументы команды и переменные окружения не могут содержать эти байты, поскольку они являются строками с разделителями NUL, передаваемыми
execve
системному вызову.Также обратите внимание, что:
или его современная форма:
удаляет все завершающие символы новой строки из вывода
cmd
. Таким образом, если этот двоичный вывод заканчивается в 0xa байтах, он будет искажен при сохранении в$var
.Здесь вам нужно хранить закодированные данные, например, с помощью
xxd -p
.Вы можете определить вспомогательные функции, такие как:
xxd -p
вывод не занимает мало места, так как он кодирует 1 байт в 2 байта, но он облегчает манипуляции с ним (конкатенация, извлечение частей).base64
это тот, который кодирует 3 байта в 4, но с ним не так легко работать.ksh93
Оболочка имеет встроенную команду формат кодирования (использованиеbase64
) , которые вы можете использовать своиread
иprintf
/print
коммунальные услуги:Теперь, если нет транзита через переменные оболочки или env или аргументы команды, вы должны быть в порядке, пока используемые вами утилиты могут обрабатывать любое значение байта. Но обратите внимание, что для текстовых утилит большинство реализаций, не относящихся к GNU, не могут обрабатывать байты NUL, и вы захотите зафиксировать локаль в C, чтобы избежать проблем с многобайтовыми символами. Последний символ, не являющийся символом новой строки, также может вызвать проблемы, а также очень длинные строки (последовательности байтов между двумя байтами 0xa, которые длиннее
LINE_MAX
).head -c
где он доступен, здесь должно быть все в порядке, так как он предназначен для работы с байтами и не имеет смысла рассматривать данные как текст. Такдолжно быть хорошо. На практике, по крайней мере, встроенные реализации GNU, FreeBSD и ksh93 в порядке. POSIX не указывает
-c
опцию, но говорит, чтоhead
должен поддерживать строки любой длины (не ограничиваясьLINE_MAX
)С
zsh
:Или:
Даже
zsh
если, если он$var
содержит NUL-байты, вы можете передать его как аргументzsh
встроенным (какprint
описано выше) или функциям, но не как аргументы исполняемым файлам, поскольку аргументы, передаваемые исполняемым файлам, являются строками с разделителями NUL, это ограничение ядра, независимое от оболочки.источник
zsh
это не единственная оболочка, которая может хранить один или несколько байтов NUL в переменной оболочки.ksh93
может сделать это тоже. Внутреннеksh93
просто хранит двоичную переменную в виде строки в кодировке base64.Ну да. Но, возможно, вам следует рассмотреть очень важную причину НЕ делать этого. По сути, «bash» / «sh» / «csh» / «ksh» и тому подобное не предназначены для обработки двоичных данных и не являются большинством стандартных утилит UNIX / LINUX.
Вам лучше либо придерживаться C ++, либо использовать язык сценариев, такой как Python, Ruby или Perl, который способен работать с двоичными данными.
Лучше не делать это в bash.
источник
ffmpeg
,imagemagick
,dd
). Теперь, если кто-то занимается программированием, а не склеивает что-то вместе, тогда лучше использовать полноценный язык программирования.Из вашего вопроса:
Если вы копируете 988 строк, то это похоже на текстовый файл, а не на двоичный файл. Однако ваш код, кажется, принимает 988 байтов, а не 988 строк, поэтому я буду считать, что байты верны.
Эта часть может не работать. Во-первых, любые байты NUL в потоке будут удалены, поскольку вы используете
${hdr_988}
аргумент командной строки, а аргументы командной строки не могут содержать NUL. Обратные галочки могут также делать пробелы (я не уверен в этом). (На самом деле, посколькуecho
это встроенное, ограничение NUL может не применяться, но я бы сказал, что оно все еще сомнительно.)Почему бы просто не записать заголовок непосредственно из входного файла в выходной файл, не передав его через переменную оболочки?
Или, более переносимо,
Поскольку вы упоминаете, что используете
bash
, а не оболочку POSIX, у вас есть доступная подстановка процессов, так как насчет этого в качестве теста?Наконец: рассмотрите возможность использования
$( ... )
вместо обратных галочек.источник
dd
это не обязательно эквивалентноhead
для нестандартных файлов.head
будет делать столькоread(2)
системных вызовов, сколько необходимо, чтобы получить эти 988 байтов, в то время какdd
просто сделает одинread(2)
. У GNUdd
естьiflag=fullblock
попытка прочитать этот блок полностью, но тогда он еще менее переносим, чемhead -c
.