Pbrun: Терминал защищен и является продуктом SUN.
sudo: пользователь защищен вместо терминала, и это продукт Solaris.
Я амбициозно пытаюсь перевести код на 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 может не применяться, но я бы сказал, что это все еще сомнительно.)
Почему бы просто не записать заголовок непосредственно из входного файла в выходной файл, не передавая его через переменную оболочки?
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}")
Наконец: рассмотрите , используя $ (...)
вместо обратные кавычки.
Работа с двоичными данными на низком уровне в сценариях оболочки обычно является плохой идеей.
Переменные 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
output не занимает много места, поскольку он кодирует 1 байт в 2 байта, но упрощает манипуляции с ним (объединение, извлечение частей). base64
- это тот, который кодирует 3 байта в 4, но с ним не так просто работать.
Оболочка ksh93
имеет встроенный формат кодирования (использует base64
), который вы можете использовать с его read
и printf
/ print
utilities:
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, что является ограничением ядра, не зависящим от оболочки.