The Linux Rain Linux General/Gaming News, Reviews and Tutorials

BASH a block of bytes

By Bob Mesibov, published 24/04/2017 in Tutorials


I was preparing a slide presentation and wanted to show a block of random 8-bit bytes, like this:

Naturally I didn't just type out that block of text on a slide, which would have taken maybe 10 minutes, or copy and modify some byte-text I found online. Of course not. Instead I spent hours dreaming up elaborate ways to do it with BASH one-liners. Three methods are described here, but there are undoubtedly dozens of others. Feel free to suggest more elegant BASH one-liners in the comments.

To standardise the task, it's this: print six separate lines, each of which has six randomly generated 8-bit bytes separated by a single whitespace, as in the image above.

Blank the ninth

for i in {1..6}; do echo $(for j in {1..53}; do echo -n $((RANDOM %2)); done | sed 's/\(.\{8\}\)./\1 /g'); done

The core of the command is $((RANDOM %2)). This is BASH arithmetic with the RANDOM function, which generates a more-or-less random integer in the range 0-32767. The arithmetic then prints the remainder after division of the integer by 2. That'll be 0 for even integers and 1 for odd integers.

The process of printing a 0 or 1 is repeated 53 times in a for loop, and the results strung together in a line with echo -n:

Why 53 times? Because the next step in the command is to pipe the string to sed, which replaces every ninth character with a space. Counting the space as one character, the output is 8-1-8-1-8-1-8-1-8-1-8 characters, or 53 characters in all. In (sort of) plain English, sed looks for a string of 8 characters followed by another 1 character. It saves the string of 8 in a backreference, and the replacement for the searched-for pattern is the backreferenced string of 8 followed by a space. The replacement is done sequentially through the 53-character string with sed's "g" option:

That's one line done. To do 6 lines, we put the for loop inside another for loop, echoing its result 6 times.

Three nested loops

for i in {1..6}; do echo $(for j in {1..6}; do printf "%s " $(for k in {1..8}; do echo -n $((RANDOM %2)); done); done); done

A nice brain-boggler. This time the command echo -n $((RANDOM %2)) is looped 8 times, to produce a single 8-bit byte. This inner loop nests within another which uses printf to print 6 bytes on a line with a space after each byte; there's a space at the end of the line. This middle loop nests within another 6-times loop to generate 6 lines of 6 bytes. The echo command in this third, outer loop trims the trailing whitespace from each line, as shown in this simplified example:

Do it in decimal

for i in {1..36}; do printf "%08d\n" $(echo "ibase=10; obase=2; $(shuf -i 0-255 -n1)" | bc); done | paste -d ' ' - - - - - -

The "blank the ninth" and "three nested loops" approaches treat the bytes as simple strings of 0's and 1's. This next method generates a list of decimal numbers, then converts them to bytes and arranges the bytes in a 6 x 6 table.

The core command here is shuf -i 0-255 -n1. The "-i" option tells shuf to use as input the numbers in the range 0-255, which is the range covered by an 8-bit byte. The "-n1" option tells shuf to output just one number from the possible permutations of that list of numbers.

The shuf output is converted from decimal to binary by echoing it to bc and specifying the input and output number bases. One result shuf might put out is 33, and bc would convert it to "100001". While that's mathematically correct, it's not in 8-bit byte notation — it's missing 2 leading zeroes. So the bc output is passed to printf to add leading zeroes to any string less than 8 characters.

The whole process is repeated 36 times in a for loop to generate a more-or-less random list of 8-bit bytes. The list of 36 bytes is then neatly laid out as 6 lines of 6 spaced bytes with a paste command.



About the Author

Bob Mesibov is Tasmanian, retired and a keen Linux tinkerer.

Tags: cli bash 8-bit bytes tutorials awk bc shuf loops scripts
blog comments powered by Disqus