2

Suppose we want a minimalist one-byte per line ASCII hex dump. Under Linux using GNU od, this works:

echo foo | od -An -tx1 -w1 -v

Output:

 66
 6f
 6f
 0a

But that won't work with BSD derivatives, because the BSD od util has different flags.

What's the most portable *nix method? Failing that, what are the best available methods?

3

od is a standard command. In od -An -tx1 -w1 -v, the only thing that is not POSIX is the -w option.

You can replace it with:

od -An -vtx1 | LC_ALL=C tr -cs '0-9a-fA-F' '[\n*]' | grep .

Which would work in any POSIX-compliant system and does work on FreeBSD at least:

$ echo test | od -An -vtx1 | LC_ALL=C tr -cs 0-9a-fA-F '[\n*]' | grep .
74
65
73
74
0a

Or with one sed invocation to replace the tr+grep:

od -An -vtx1 | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//;/./!d
s/[[:blank:]]\{1,\}/\
/g'

(or

od -An -vtx1 | sed -n 's/[[:blank:]]*\([^[:blank:]]\{2\}\)[[:blank:]]*/\1\
/g;s/\n$//p'

)

With perl (not a POSIX command but ubiquitous on anything but embedded systems):

perl -ne '
  BEGIN{$/ = \8192; $, = $\ = "\n"}
  print  unpack "(H2)*", $_'

Which is also the fastest of the 3 in my tests (compared to GNU od) by a significant margin for anything but small files (also than hexdump, not than vim's xxd).

  • Useful, but post-od it needs two pipes. Would you know if this one-pipe version: od -An -tx1 | grep -o '[^ ].' is as portable? – agc Sep 28 '16 at 11:16
  • 1
    @agc, grep -o is a GNU extension. BSDs grep is based on GNU grep (now rewritten) but other Unix-likes generally don't have it. It should be doable with one sed instead of tr+grep. – Stéphane Chazelas Sep 28 '16 at 12:11
  • Works on Linux, od -An -vtx1 | sed 's/[[:blank:]]\(..\)/\1\n/g;s/.$//', don't know about elsewhere... – agc Sep 28 '16 at 19:00
  • 1
    @agc, \n on the right-hand side of a s command is not POSIX and not portable. The amount of blanks between numbers is also unspecified (typically that command won't work at all on FreeBSD). I can see that Solaris od adds an extra blank line at the end, and FreeBSD adds extra spaces at the end of each line so I also need to adapt my sed version. – Stéphane Chazelas Sep 28 '16 at 20:23
1

Maybe hexdump:

$ echo foo | hexdump -v -e '1/1 "%02x\n"'
66
6f
6f
0a

Which is original from BSD its manual is here (in BSD).

However the example shown above was run in Linux.

0

xxd exists in Linux, BSD, and OSX:

echo foo | xxd -p -c 1
66
6f
6f
0a

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.