Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.
Perl and bash examples

So, all these are good examples but need a little touchup for them to run properly.

The first bash example will only work if you enumerate the files. Simply putting
for i in *.jpg
won't do anything. The correct example would be:

Code:
for i in `ls *.jpg`; do mv $i $RANDOM.jpg; done

The 2nd bash example has the problem, at least on my system, that extraneous spaces are added to the beginning and end of the od example. To illustrate, the following code

Code:
echo "'`od -An -N2 -i /dev/random`'"

generates

'(14spaces)-1606221824(48spaces)'

Obviously, this won't work with rename (mv). So you can strip all the spaces with tr:

Code:
echo "'`od -An -N2 -i /dev/random | tr -d " "`'"

So the final script could be:

Code:
for i in `ls *.jpg`; do mv $i `od -An -N2 -i /dev/random | tr -d " "`.jpg; done

Finally, a perl script posted by jeremias at http://ask.metafilter.com/78113/How-to-create-a-unique-osx-automator-action-that-randomly-renames-files works almost as posted. Allowing one to supply the directory as a command line argument and removing file/directory handle barewords, the following script works as he intended:

Code:
#!/usr/bin/perl -w
#

my $path 		= shift || die "Directory name must be supplied as an argument!\n";
opendir (my $DIR, $path);
my @files 		= grep { /\.jpg/i } readdir($DIR); # get list of all jpegs in that directory

@files 			= sort {(rand 2) <=> 1} @files; # randomize it
for ($i = 0; $i < scalar @files ; $i++) {
	$old 		= $files[$i];
	$new 		= $old;
	$new 		=~ s#^\d*__##; # remove earlier modifications, so you can run this twice
	# prepend a random number and two underscores to the filename
	$new 		= $i . "__" . $new; 
	print "renaming $old to $new\n";
	rename("$path/$old", "$path/$new") or warn("Couldn't rename $old to $new"); # rename the file
}

Kudos to the three authors for doing most of the work!!
 
Just a bit extra

Thanks for the terminal command—this is exactly what I wanted.

There were some issues though, the same as what codenewbie had in his/her attempts. I found that these were caused by filenames with spaces in them. To remedy this, I found it necessary to put quote marks around the $i variable.

This should take care of all problems now. I think.

Code:
for i in `ls *.jpg`; do mv "$i" `od -An -N2 -i /dev/random | tr -d " "`.jpg; done

Hope someone benefits from this!
 
Need updated code please to prevent overwriting files

Thank you all for this ongoing post, even if it was years ago. I too am trying to use Terminal to do a batch (random) rename of 2300 pictures for a digital photo frame.

I have successfully used the expanded code (pasted below) to successfully do this, but I did notice that an obvious overwrite took place. The folder no longer had 2330 pictures, but 2250.

After I had made this mistake and researched further, I noticed a comment on this post suggested to also include "mv -n" within the code so as to prevent anything from getting overwritten. For those of us who are not as comfortable creating code, would someone mind re-pasting the exact code that we could paste into the terminal command once the correct (photo) directory is chosen within Terminal? That would be great.

Below is the code I used, which does successfully randomly rename batch files, but DOES NOT prevent the files from being overwritten as they are randomly renamed:


for i in `ls *.jpg`; do mv "$i" `od -An -N2 -i /dev/random | tr -d " "`.jpg; done


What should the updated code be in order to no longer overwrite files as they are randomly renamed?

Many thanks,
 
RE: random ...

He evanpcarter,

While the run length before repetition of /dev/random should be much longer than the number of files you would typically rename, if you are worried about it then you might either use the -i (which will send an interactive prompt to stderr before overwriting a file) or the -n (which will not overwrite the file) option for the "mv" command. Besides that, everything is the same.

Regards,
Switon
 
Thanks Switon,

I wish I knew how to translate that into actual code, but I'm still not sure. Would you mind just pasting the entire code that I would copy an paste into Terminal?

Again, I really appreciate your help!
 
  • Like
Reactions: rawar777
RE: the Terminal command to use...

Thanks Switon,

I wish I knew how to translate that into actual code, but I'm still not sure. Would you mind just pasting the entire code that I would copy an paste into Terminal?

Again, I really appreciate your help!

Hi evanpcarter,

Here is the Terminal command line:

Code:
for i in `ls *.jpg`; do mv -n "$i" `od -An -N2 -i /dev/random | tr -d " "`.jpg; done

Basically, the "-n" option to the rename command, "mv", just tells "mv" not to overwrite a file that already exists, while the "-i" option to "mv" (substitute -i for -n in the above command) will provide an interactive prompt asking for your input if the "mv" ever tries to overwrite a file.

Caveat: I just tested this command, and it works properly to rename JPEG files having extensions .jpg to randomly numbered JPEG files, such as 36582.jpg, etc. Because no "overwrites" occurred in my testing, I did not test that this command works when overwrites are encountered, but it should work since the "mv -n" works properly. Again, I doubt that you will ever actually encounter an overwrite when using /dev/random, but just in case the -n or -i options will prevent it from occurring.

Regards,
Switon

Edit: Let's quickly explain how this bash shell command works, shall we? First of all the `ls *.jpg` does a directory listing for all files in the directory ending in '.jpg' (the * is a wild card that matches any pattern). The 'for i in' is a FOR statement, it sets the variable 'i' to each object in succession in the directory listing given by `ls *.jpg`. The next part of the command after the semicolon, tells the FOR statement what to do, it says to rename the file given in the 'i' variable ("$i") to something else: 'mv -n "$i" '. What should the file be renamed to? Well that is determined by '/dev/random', a random number generator. The output of the random number generator is first processed by 'od', the "octal dump" command. This command takes the output of 'dev/random' and first specifies a no address base ('-An') and to use only two bytes ('-N2') of the random number. The output of the 'od' command is piped ('|'), that is, sent as input to the translate character ('tr') command. The 'tr' command deletes any spaces ('-d " "') in the output of the 'od' command, and the whole thing is prepended to '.jpg', that is, a filename consisting of random numbers two bytes long appended with '.jpg' is generated and supplied to the rename command ('mv -n'). Thus each of the original '*.jpg' files in the directory is renamed to a randomly generated filename. The '; done' portion just tells the bash shell that the FOR/DO statement is done.
 
Last edited:
You guys are truly speaking another language to me. Thank you so much for providing this command! I have over 900 photos that I'm putting into iMovie to to make a fun slide show for my wife. The first time I ran the command it did about a 3rd of my pictures and I think I finally found out why it didn't do the rest. It is either because of the case sensitivity (.jpg vs. .JPG), or the fact that the rest of my pictures had spaces, dashes, underscores or apostrophes in the names. I did a rename for each of these situations to get rid of those characters and ran the command again. Now I'm getting htis error:
-bash: command substitution: line 2: syntax error: unexpected end of file

-bash: command substitution: line 1: unexpected EOF while looking for matching `"'

So now I'm stuck again...


RE: the Terminal command to use...



Hi evanpcarter,

Here is the Terminal command line:

Code:
for i in `ls *.jpg`; do mv -n "$i" `od -An -N2 -i /dev/random | tr -d " "`.jpg; done

Basically, the "-n" option to the rename command, "mv", just tells "mv" not to overwrite a file that already exists, while the "-i" option to "mv" (substitute -i for -n in the above command) will provide an interactive prompt asking for your input if the "mv" ever tries to overwrite a file.

Caveat: I just tested this command, and it works properly to rename JPEG files having extensions .jpg to randomly numbered JPEG files, such as 36582.jpg, etc. Because no "overwrites" occurred in my testing, I did not test that this command works when overwrites are encountered, but it should work since the "mv -n" works properly. Again, I doubt that you will ever actually encounter an overwrite when using /dev/random, but just in case the -n or -i options will prevent it from occurring.

Regards,
Switon

Edit: Let's quickly explain how this bash shell command works, shall we? First of all the `ls *.jpg` does a directory listing for all files in the directory ending in '.jpg' (the * is a wild card that matches any pattern). The 'for i in' is a FOR statement, it sets the variable 'i' to each object in succession in the directory listing given by `ls *.jpg`. The next part of the command after the semicolon, tells the FOR statement what to do, it says to rename the file given in the 'i' variable ("$i") to something else: 'mv -n "$i" '. What should the file be renamed to? Well that is determined by '/dev/random', a random number generator. The output of the random number generator is first processed by 'od', the "octal dump" command. This command takes the output of 'dev/random' and first specifies a no address base ('-An') and to use only two bytes ('-N2') of the random number. The output of the 'od' command is piped ('|'), that is, sent as input to the translate character ('tr') command. The 'tr' command deletes any spaces ('-d " "') in the output of the 'od' command, and the whole thing is prepended to '.jpg', that is, a filename consisting of random numbers two bytes long appended with '.jpg' is generated and supplied to the rename command ('mv -n'). Thus each of the original '*.jpg' files in the directory is renamed to a randomly generated filename. The '; done' portion just tells the bash shell that the FOR/DO statement is done.
 
You guys are truly speaking another language to me. Thank you so much for providing this command! I have over 900 photos that I'm putting into iMovie to to make a fun slide show for my wife. The first time I ran the command it did about a 3rd of my pictures and I think I finally found out why it didn't do the rest. It is either because of the case sensitivity (.jpg vs. .JPG), or the fact that the rest of my pictures had spaces, dashes, underscores or apostrophes in the names. I did a rename for each of these situations to get rid of those characters and ran the command again. Now I'm getting htis error:
-bash: command substitution: line 2: syntax error: unexpected end of file

-bash: command substitution: line 1: unexpected EOF while looking for matching `"'

So now I'm stuck again...
Try this instead of the command-line posted by switon:
Code:
for i in *.jpg; do mv -n "$i" `od -An -N2 -i /dev/random | tr -d " "`.jpg; done

It's similar, but starts a little differently.

This command is case-sensitive. It won't process files whose extension is ".JPG", only those with ".jpg". If you want a solution for that, ask again.


If the above doesn't solve the problem, you're probably going to have to tell us the filename of the file that's causing the command to fail. To do that:
  1. Make a new folder.
  2. Move all the jpg files that WERE renamed into the new folder.
    You can tell which these are because they'll have numeric filenames.
  3. Run the command again, and confirm it fails.
    If it doesn't fail, stop and post here, saying it didn't fail.
  4. Copy and paste this command into the Terminal window:
    Code:
    ls -1 *.jpg | head -n 10
  5. Select, copy, and paste the commands and output from steps 3 & 4 and post it here.
 
  • Like
Reactions: Weaselboy
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.