Все представленные ответы относятся к удобному подходу xxd -r
, но для ситуаций, когда xxd
недоступен или удобен, здесь более переносимое (и более гибкое, но более подробное и менее эффективное) решение, использующее только POSIX. Синтаксис оболочки (он также компенсирует нечетное количество цифр на входе):
un_od() {
printf -- "$(
tr -d '\t\r\n ' | sed -e 's/^(.(.{2})*)$/0\1/' -e 's/\(.\{2\}\)/\\x\1/g'
)"
}
Между прочим: вы не указываете, является ли ваш ввод байтов с прямым порядком байтов или байтов с прямым порядком байтов, или хотите ли вы вывод с большим / младшим порядком байтов. Обычно входные данные, такие как в вашем вопросе, будут иметь порядок с прямым порядком байтов / сетью (например, созданный od -t x1 -An -v
), и ожидается, что они преобразуются в выходные данные с прямым порядком байтов. Я предполагаю, что xxd
просто предполагает, что по умолчанию, если не указано иное, и это решение делает то же самое. Если требуется замена байтов, то как вы делаете замену байтов, также зависит от размера слова в системе (например, 32-битная, 64-битная) и очень редко - байтовый размер (вы можете почти всегда предполагать 8-битную байты - октеты - хотя).
В приведенных ниже функциях используется более сложная версия трюка binary -> od -> binary
для переноса байтных данных с байт-свопом, с учетом системного порядка байтов и учета системного размера слова. Алгоритм работает для всего до 72-битного слова (потому что seq -s '' 10
-> 12345678910
не работает):
if { sed --version 2>/dev/null || :; } | head -n 1 | grep -q 'GNU sed'; then
_sed() { sed -r "${@}"; }
else
_sed() { sed -E "${@}"; }
fi
sys_bigendian() {
return $(
printf 'I' | od -t o2 | head -n 1 | \
_sed -e 's/^[^ \t]+[ \t]+([^ \t]+)[ \t]*$/\1/' | cut -c 6
)
}
sys_word_size() { expr $(getconf LONG_BIT) / 8; }
byte_swap() {
_wordsize=$1
od -An -v -t o1 | _sed -e 's/^[ \t]+//' | tr -s ' ' '\n' | \
paste -d '\\' $(for _cnt in $(seq $_wordsize); do printf -- '- '; done) | \
_sed -e 's/^/\\/' -e '$ s/\\+$//' | \
while read -r _word; do
_thissize=$(expr $(printf '%s' "$_word" | wc -c) / 4)
printf '%s' "$(seq -s '' $_thissize)" | tr -d '\n' | \
tr "$(seq -s '' $_thissize -1 1)" "$_word"
done
unset _wordsize _prefix _word _thissize
}
Вы можете использовать вышеперечисленное для вывода содержимого файла в бигендовском формате независимо от системного порядка байтов:
if sys_bigendian; then
cat /bin/sh
else
cat /bin/sh | byte_swap $(sys_word_size)
fi