Как я могу работать с двоичным в bash, чтобы скопировать байты дословно без какого-либо преобразования?

Я амбициозно пытаюсь перевести код 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-двоичном файле, скопировать в файл дословно? (и в идеале хранить как переменные).

  • Как я могу раскрасить голову, хвост и меньше, как я сделал с кошкой?
  • Каков способ POSIX для чтения точного количества байтов из файла?
  • Заголовок POSIX и хвост не соответствуют эквиваленту
  • Объяснение вывода скрипта
  • 3 Solutions collect form web for “Как я могу работать с двоичным в bash, чтобы скопировать байты дословно без какого-либо преобразования?”

    Работа с двоичными данными на низком уровне в сценариях оболочки обычно является плохой идеей.

    переменные bash не могут содержать байт 0. zsh – единственная оболочка, которая может хранить этот байт в своих переменных.

    В любом случае аргументы команды и переменные окружения не могут содержать эти байты, поскольку они представляют собой строки с разделителями NUL, переданные execve вызову 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 (например, выше) или функций, но не как аргументы для исполняемых файлов, поскольку аргументы, переданные исполняемым файлам, представляют собой строки с разделителями NUL, это ограничение ядра, независимо от оболочки.

    Я амбициозно пытаюсь перевести код c ++ в bash по множеству причин.

    Ну да. Но, возможно, вы должны рассмотреть очень важную причину, чтобы НЕ делать это. В принципе, «bash» / «sh» / «csh» / «ksh» и т. Д. Не предназначены для обработки двоичных данных, и ни одна из них не является стандартными утилитами UNIX / LINUX.

    Вам было бы лучше либо придерживаться C ++, либо использовать язык сценариев, такой как Python, Ruby или Perl, который способен обрабатывать двоичные данные.

    Есть ли лучший способ сделать это в bash?

    Лучше всего не делать этого в bash.

    Из вашего вопроса:

    скопируйте первые 988 строк заголовка

    Если вы копируете 988 строк, это похоже на текстовый файл, а не двоичный. Тем не менее, ваш код, кажется, предполагает 988 байт, а не 988 строк, поэтому я предполагаю, что байты правильные.

     hdr_988=`head -c 988 ${inputFile}` echo -n "${hdr_988}" > ${output_hdr} 

    Эта часть может не работать. Во-первых, любые NUL-байты в потоке будут разделены, потому что вы используете ${hdr_988} в качестве аргумента командной строки, а аргументы командной строки не могут содержать NUL. Выходы могут также выполняться без пробелов (я не уверен в этом). (На самом деле, поскольку echo является встроенным, ограничение NUL может не применяться, но я бы сказал, что это все равно iffy.)

    Почему бы просто написать заголовок непосредственно из входного файла в выходной файл, не передавая его через переменную оболочки?

     head -c 988 "${inputFile}" >"${output_hdr}" 

    Или, более переносимо,

     dd if="${inputFile}" of="${output_hdr}" bs=988 count=1 

    Поскольку вы упоминаете, что используете bash , а не оболочку POSIX, у вас есть подстановка процесса, доступная вам, поэтому как насчет этого в качестве теста?

     cmp <(head -c 988 "${inputFile}") <(head -c 988 "${output_hdr}") 

    Наконец: рассмотрим использование $( ... ) вместо обратных ссылок.

    Interesting Posts

    Как работает процесс установки linux

    Регулярные выражения с ExpectJ

    Дважды щелкните Shell Script в Ubuntu 16.04 Nautilus дает пользователю возможность редактировать файл сценария оболочки

    Перемещенная папка в другую теперь исчезла

    Услуги автозапуска после аварии в rhel 6

    Rsyslog не создает файлы журналов

    mutt: thread, отсортированный по последней активности, но упорядоченные по почте рассылки

    локальный кеш пакетов для арки linux

    Как настроить принтер HP в CUPS?

    Получение пользовательского ввода из сценария, используемого как stdin для сеанса SSH

    Может ли linux использовать сочетание паролей SHA-1 и CRYPT?

    Неправильное количество полос движения через DisplayPort, возможно, проблема с драйвером Nvidia GTX 1080

    Запуск всех сценариев в папке в фоновом режиме

    перенаправление портов на внутренний LAN-сервер

    Ubuntu – блокирует доступ в Интернет для всех приложений, за исключением избранных

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