Today I had the need to reverse a binary stream using only bash and commonly-available command-line utilities. Not tac, sed, or rev, which are all line-oriented utilities that work best on ASCII data. I needed something that I could trust with binary data. This is what I came up with. Feel free to point out my weakness.
The first round was this:
reverse() {
local i=0
cat | xxd -c 1 | awk '{print $2}' | tac |
while read F; do
printf "%06x: %sn" $i $F; i=$((i+1))
done | xxd -c 1 -r
}
I wasn’t a huge fan of the while loop to prefix the lines with addresses for ‘xxd -r’. The streams that I am using this for are only several kB max, so efficiency was not my first goal, but why not try to make it faster if you have the option? Some reading reveals that ‘tac’ is not available on every Unix platform. And ‘xxd’ is only available if you have vim installed. I swapped in ‘hexdump’ for ‘xxd’, but hexdump does not have a reverse, so I had to find a way to do that. This is where awk comes into play, doing and integer to character conversion for each line. This happens to run in about 6 times faster than the original version and uses stuff that even busybox has.
My final version was this:
reverse() {
cat | hexdump -v -e '/1 "%dn"' |
sed -e '1!G;h;$!d' |
awk '{printf "%c", $0}'
}
You might use it like this:
$ reverse file.reversed
# or
$ command -in -a | pipeline | reverse | process | reverse > some_output