Show Hexadecimal Numbers Of a File
Edit: Added "bytestream" functionality. If the script name contains the word "stream" (e.g. it's a symlink such as ln -s bash-hexdump bash-hexdump-stream
and run as ./bash-hexdump-stream
), it will output a continuous stream of hex characters representing the contents of the file. Otherwise its output will look like hexdump -C
.
It takes a bunch of trickery since Bash isn't really good at binary:
#!/bin/bash# bash-hexdump# by Dennis Williamson - 2010-01-04# in response to http://stackoverflow.com/questions/2003803/show-hexadecimal-numbers-of-a-file# usage: bash-hexdump fileif [[ -z "$1" ]]then exec 3<&0 # read stdin [[ -p /dev/stdin ]] || tty="yes" # no pipeelse exec 3<"$1" # read filefi# if the script name contains "stream" then output will be continuous hex digits# like hexdump -ve '1/1 "%.2x"'[[ $0 =~ stream ]] && nostream=false || nostream=truesaveIFS="$IFS"IFS="" # disables interpretation of \t, \n and spacesaveLANG="$LANG"LANG=C # allows characters > 0x7Fbytecount=0valcount=0$nostream && printf "%08x " $bytecountwhile read -s -u 3 -d '' -r -n 1 char # -d '' allows newlines, -r allows \do ((bytecount++)) printf -v val "%02x" "'$char" # see below for the ' trick [[ "$tty" == "yes" && "$val" == "04" ]] && break # exit on ^D echo -n "$val" $nostream && echo -n " " ((valcount++)) if [[ "$val" < 20 || "$val" > 7e ]] then string+="." # show unprintable characters as a dot else string+=$char fi if $nostream && (( bytecount % 8 == 0 )) # add a space down the middle then echo -n " " fi if (( bytecount % 16 == 0 )) # print 16 values per line then $nostream && echo "|$string|" string='' valcount=0 $nostream && printf "%08x " $bytecount fidoneif [[ "$string" != "" ]] # if the last line wasn't full, pad it outthen length=${#string} if (( length > 7 )) then ((length--)) fi (( length += (16 - valcount) * 3 + 4)) $nostream && printf "%${length}s\n" "|$string|" $nostream && printf "%08x " $bytecountfi$nostream && echoLANG="$saveLANG";IFS="$saveIFS"
The apostrophe trick is documented here. The relevant part says:
If the leading character is a single-quote or double-quote, the value shall be the numeric value in the underlying codeset of the character following the single-quote or double-quote.
Here is some output from the script showing the first few lines of my /bin/bash
plus a few more:
00000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|00000010 02 00 03 00 01 00 00 00 e0 1e 06 08 34 00 00 00 |............4...|00000020 c4 57 0d 00 00 00 00 00 34 00 20 00 09 00 28 00 |.W......4. ...(.|00000030 1d 00 1c 00 06 00 00 00 34 00 00 00 34 80 04 08 |........4...4...|. . .00000150 01 00 00 00 2f 6c 69 62 2f 6c 64 2d 6c 69 6e 75 |..../lib/ld-linu|00000160 78 2e 73 6f 2e 32 00 00 04 00 00 00 10 00 00 00 |x.so.2..........|00000170 01 00 00 00 47 4e 55 00 00 00 00 00 02 00 00 00 |....GNU.........|