Reputation: 85
I am trying to generate a random string with the following code:
for pic in `ls *.jpg`; do
rdn=`echo $RANDOM | sha256sum | cut -d" " -f1`
mv "$pic" ${rnd}.jpg
done
This part of the script runs from within a directory containing lots of jpeg files and it should randomize their filenames. The problem is that the $RANDOM
variable does not update during the iteration, and therefore gives the same hash every time. I tried to use /dev/urandom
, and it works, but is a lot slower than $RANDOM
. What can I do to "regenerate" $RANDOM
every time it is read?
Upvotes: 6
Views: 9284
Reputation: 2786
On my mac (using macOS High Sierra), the /dev/urandom
gives me binary bytes, so the above solution results in tr: Illegal byte sequence
, so I used base64
to convert bytes to characters:
cat /dev/urandom | base64 | tr -dc '0-9a-zA-Z' | head -c100
or I found a solution without base64 so you can get punctuation as well:
cat /dev/urandom | LC_ALL=C tr -dc '\''[:alnum:]\!\@\#$\-\.\,'\'' | head -c40
Upvotes: 10
Reputation: 4532
You can do this more simply just using cat, tr and head. For example:
cat /dev/urandom | tr -dc '0-9a-zA-Z' | head -c100
The tr
command in this pipeline will delete any character from stdin which does not match the specified character set. The head
will print the first 100 characters and then exit, terminating the overall command.
This will generate a 100 character string containing alphanumeric characters. To make this into a rename you just need to use command substitution:
for file in *.jpg
mv -n ${file} $(cat /dev/urandom | tr -dc '0-9a-zA-Z' | head -c100).jpg
In zsh a for
loop with a single statement does not need to be surrounded with do
or done
. The -n
flag to mv will prevent it from overwriting an existing file - just in case you get really unlucky with the random strings.
Upvotes: 6
Reputation: 77167
for pic in *.jpg; do # Iterate over the jpgs in the current directory.
dd if=/dev/urandom count=1 2>/dev/null | sha256sum | ( # Gather 512 bytes from /dev/urandom
read rnd _ # Read the first "word" in the sha256sum output
mv "$pic" ${rnd}.jpg # rename the jpg.
)
done
Piping to read
causes an implicit subshell, so I create an explicit subshell to guarantee I can still access the rnd
parameter. Also, don't parse ls
By the way, are you sure you don't just want to base64
the output? It's cheaper than sha256sum by far and I don't see what you're getting out of sha256sum. Plus it'd make the code easier to read:
for pic in *.jpg; do
mv "$pic" "$(base64 </dev/urandom | tr -dc 'a-zA-Z0-9' | head -c20).jpg"
done
Upvotes: 1