What's the opposite of od(1)?

What's the opposite of od(1)?

疾风者 发布于 2021-11-28 字数 206 浏览 805 回复 5 原文

Say I have 8b1f 0008 0231 49f6 0300 f1f3 75f4 0c72 f775 0850 7676 720c 560d 75f0 02e5 ce00 0861 1302 0000 0000, how can I easily get a binary file from that without copying+pasting into a hex editor?

如果你对这篇文章有疑问,欢迎到本站 社区 发帖提问或使用手Q扫描下方二维码加群参与讨论,获取更多帮助。

扫码加入群聊

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

歌枕肩 2022-06-07 5 楼

Here is the way to reverse "od" output :

echo "test" | od -A x -t x1 | sed -e 's|^[0-f]* ?||g' | xxd -r
test
樱桃奶球 2022-06-07 4 楼

All the present answers refer to the convenient xxd -r approach, but for situations where xxd is not available or convenient here is a more portable (and more flexible, but more verbose and less efficient) solution, using only POSIX shell syntax (it also compensates for odd-number of digits in input):

un_od() {
    printf -- "$(
        tr -d 'trn ' | sed -e 's/^(.(.{2})*)$/01/' -e 's/(.{2})/\x1/g'
    )"
}

By the way: you don't specify whether your input is big-endian or little-endian, or whether you want big/little-endian output. Usually input such as in your question would be big-endian/network-order (e.g. as created by od -t x1 -An -v), and would be expected to transform to big-endian output. I presume xxd just assumes that default if not told otherwise, and this solution does that too. If byte-swapping is needed, how you do the byte-swapping also depends on the word-size of the system (e.g. 32bit, 64bit) and very rarely the byte-size (you can almost always assume 8bit bytes - octets - though).

The below functions use a more complex version of the binary -> od -> binary trick to portably byteswap binary data, conditional on system endianness, and accounting for system word-size. The algorithm works for anything up to 72bit word-size (because seq -s '' 10 -> 12345678910 doesn't work):

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
}

You can use the above to output file contents in bigendian format regardless of system endianness:

if sys_bigendian; then
    cat /bin/sh
else
    cat /bin/sh | byte_swap $(sys_word_size)
fi
冷︶言冷语的世界 2022-06-07 3 楼

This version will work with binary format too :

cat /bin/sh 
| od -A n -v -t x1 
| tr -d 'r' 
| xxd -r -g 1 -p1 
| md5sum && md5sum /bin/sh

The extra 'r' is just if you're dealing w/ dos text files...
and process byte by byte to prevent endians difference if running parts of pipe on different systems.

转瞬即逝 2022-06-07 2 楼

See xxd.

泼猴你往哪里跑 2022-06-07 1 楼

Use:

% xxd -r -p in.txt out.bin