shellcheck --version or "online"):#!/bin/bash
key_string=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 40 | head -n 1)
^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.
Shellcheck is perfectly correct; cat is indeed a pointless additional process in that pipeline; a shorter (and slightly more efficient) equivalent would be:
key_string=$( tr -dc a-zA-Z90-9 < /dev/urandom | fold -w 40 | head -n1 )
Having said that, this oft-cited technique for getting printable random strings is extremely poor from a cryptographic perspective: I would go further and say this is not just a _useless_ use of cat, this is a _harmful_ use of cat.
The cat command, in trying to be efficient with large files, attempts to read (and actually receives) many kilobytes, most of which is then eventually discarded by head. In doing so, it spills most (or very likely _all_) of your system's secured entropy pool, which impacts other processes that need secure entropy. (The same is true of most commands, including tr, as they use stdio and the buffering provided by libc.so.)
Instead, consider reading only the 240 bits you actually need, and using base64 to convert that to a printable key:
key_string=$( head -c30 </dev/urandom | base64 -w0 )
If you _really_ don't want the + & / symbols in your key values, simply substitute other symbols:
key_string=$( head -c30 </dev/urandom | base64 -w0 )
key_string=${key_string//\//X}
key_string=${key_string//+/Y}
(If you cared enough to worry about the bias that this introduces, you'd be using /dev/random instead of /dev/urandom and then the speed reduction due to entropy spilling would be _really_ noticeable.)
Shellcheck is right -- you can drop this cat. Kurahaupo does an even better job explaining interesting deeper issues.
It rarely affects correctness though, so whether you care about the performance or the 20+ year old Useless Use Of Cat shell meme is up to you.
Thank you both!
Most helpful comment
Shellcheck is perfectly correct;
catis indeed a pointless additional process in that pipeline; a shorter (and slightly more efficient) equivalent would be:Having said that, this oft-cited technique for getting printable random strings is extremely poor from a cryptographic perspective: I would go further and say this is not just a _useless_ use of cat, this is a _harmful_ use of
cat.The
catcommand, in trying to be efficient with large files, attempts to read (and actually receives) many kilobytes, most of which is then eventually discarded byhead. In doing so, it spills most (or very likely _all_) of your system's secured entropy pool, which impacts other processes that need secure entropy. (The same is true of most commands, includingtr, as they use stdio and the buffering provided bylibc.so.)Instead, consider reading only the 240 bits you actually need, and using
base64to convert that to a printable key:If you _really_ don't want the
+&/symbols in your key values, simply substitute other symbols:(If you cared enough to worry about the bias that this introduces, you'd be using
/dev/randominstead of/dev/urandomand then the speed reduction due to entropy spilling would be _really_ noticeable.)