4

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?

countermode
  • 7,373
  • 5
  • 31
  • 58
agc
  • 7,045
  • 3
  • 23
  • 53

3 Answers3

4

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).

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • 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
  • A simpler and more readable approach: `od -An -vtx1 |xargs printf '%s\n'` – michau Jul 05 '19 at 15:50
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.

1

xxd exists in Linux, BSD, and OSX:

echo foo | xxd -p -c 1
66
6f
6f
0a
agc
  • 7,045
  • 3
  • 23
  • 53