I am trying to make a bash script for OSX that adds an alphanumeric extension at the end of the file.

I can't find how to make the random 6 character. Ex filename_cod_45fg43.zip

Here the script:

for fname in *.zip
 CODE= ???
 mv "$fname" "${fname%.zip}$CODESTRING.zip"

This will work:

   for fname in *.zip
        CODE="$(tr -dc '[:alnum:]' </dev/urandom | head -c 6)"
        YOUR mv CODE
  • it returns the error: tr: Illegal byte sequence – somtam Feb 28 '17 at 11:37
  • 1
    Better to use the '[:class:]' specification (see man tr) and skipping the redundant pipe. – Fiximan Feb 28 '17 at 11:49
  • @somtam hope this will help unix.stackexchange.com/a/45406/190518 – Rakesh.N Feb 28 '17 at 13:13
  • ok this does exactly what I was looking for CODE=$(LC_CTYPE=C tr -dc A-Za-z0-9 < /dev/urandom | head -c 5 | xargs) Thanks – somtam Mar 1 '17 at 5:52

You could use mktemp:

$ mktemp foobarXXXXXX
$ mktemp foobarXXXXXX
$ mktemp foobarXXXXXX

In your example perhaps that would be something like:

mv "$fname" "$(mktemp "${fname%.zip}"XXXXXX.zip)"

But you should do some testing. Strange things happen for zipfiles that end with 'X'... ;) (needs a non-X suffix/separator which I've conveniently left out in this example).

The nice thing about mktemp is that it makes sure, no matter how unlikely the chance may be, that the filename did not already exist. Of course it's useless in the example above that does not check for errors in the first place...

Or you make use of mv's builtin --backup mechanism.

(Depends on why you are doing this in the first place.)

  • It prints the XXXXX in the name. Is there a way to get the alphanumeric string instead of output it? Thanks – somtam Feb 28 '17 at 11:38
  • Oh. Try "$(mktemp "${fname%.zip}"XXXXXX)".zip instead? (Sorry, I kinda missed the OSX part of your question :) – frostschutz Feb 28 '17 at 11:45
  • Now it is working, but and the end of the process there are, for each file, a second file with 0 byte with the same name but no extension. Thanks. – somtam Feb 28 '17 at 12:42

We go to all this lengths to avoid mv-ing into an existing file and to also be able to do a fail-safe creation of a new filename which really didn't exist before and be able to own it ourselves.

umask 077; # take away perms from others + group
orig_state=$(set +o | awk '$3 == "noclobber"')
set -C; # cannot overwrite now
for fname in ./*.zip
   while :
      CODE=$(head /dev/urandom | tr -cd 'a-zA-Z0-9_' | dd bs=1 count=6 2>/dev/null)
      { > $new_name; } &>/dev/null && break
   mv -f "$fname" "$new_name"
# recover state
eval "$orig_state"
umask "$orig_umask"
  • It returns "tr: Illegal byte sequence". Thanks – somtam Feb 28 '17 at 12:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.