Friday, 4 April 2014

Is there one elegant way to do multiple file renames in linux?

Is there one elegant way to do multiple file renames in linux?
Answer: Well. Sorry. Not really. Two main techniques that should be known:
1. Discover mmv. yum install mmv; mmv \*.\* pre_\#1_post.\#2
2. Learn bash scripting. bash for loop and variable manipulation and find and sed and occasionally awk and sometimes even perl and python might be called into action. VERY flexible. But many ways to do the same thing.

Common patterns:
 for f in *; do mv $f pre_${f%%.*}_post.${f#*.}; done  # read bash manual on variable substitution
 for f in *; do nf=$(echo $f | sed "s/^/pre_/g;s/\./_post./"); mv $f $nf; done  
 for f in *; do mv $f ${f/foog/moog}; done    # substitution s/foog/moog/
 for f in *; do mv $f ${f//foog/moog}; done   # global substitution s/foog/moog/g
 ls * |xargs -I {} mv {} $(something a bit more awkward than expected!)
 ls * |xargs -I {} mv {} {}.bak # xargs fine for simple stuff BUT too awkward if wish to manipulate the string
 find . -name "*" -exec mv {} $(echo {}|sed "s/^/pre_/g;s/\./_post./"); \; # wurghh but works
 find . -name "*" |xargs -I {} mv {} STUFF # same as before for xargs 
 rename 's/\(.*\)\.\(.*\)$/pre_\1_post.\2/' *.JPG  # rename perl flavour - maybe TODO test
 rename "" pre_ *; rename . _post. *# rename linux-utils flavour, ^ doesn't work to match beginning of filename but "" does

Conclusion: learning some bash syntax is what you should do. Learn bash variable substitution and some simple sed. 

rename [options] expression replacement file...
WARNING (applies to all the renaming, use echo before mv to check your command does what is expected BEFORE you run it in anger on many files). This WARNING from linux-utils rename manpage is relevant: "The  renaming  has no safeguards.  If the user has permission to rewrite file names, the command will perform the action without any questions.  For example, the result can be quite drastic when the command is run as root in the /lib directory. Always make a backup before running the command, unless you truly know what you are doing."

The GNU/Linux Command-Line Tools Summary (see below) has a good summary of using mmv, rename (perl flavour) and bash scripting. 

There are many different ways to do the same thing with computers.
This particularily applies to linux.
In a way this is good, it allows many kinds of different uses of the same computer hardware.
In other ways it is bad.
It is a good user experience if there is one well known way of doing something.

Mac vs Windows vs Linux.  Mac more design principled also more restricted environment (for users and developers). One sw/app to do one job . . . or at least not 100 options which work 40 - 80%, very different values of working.

An example is renaming multiple files . . .

The tool to rename files in unix/linux is mv. Nice and simple. 'mv filea fileb' will rename filea to fileb. Grand. Now sometimes I want to operate on multiple files. Can I do that? 'mv *.jpg Pictures/' will move all my jpg files in current dir to Pictures/ dir. Lovely. Now how about if I have lots of files and wish to rename them all. Can I do this: 'mv DSC00*.JPG photo_*.jpg'? NO. That doesn't work.


The good old days . . . ? amstrad/ cp/m
DOS copy *.xxx *.yyy # principle of it just does what you want it to do . . .
# principle of not surprising user ~~ kindof ~~ depends on the user and how they came at the tool

UNIX higher principles on . Command line expansions are handled in one place and handled the same for all tools. One tool does one job well. But that means you cannot hijack wildcards in your utility. They are already expanded by shell before utility gets them.

UNIX newbie gotcha #1:
   'mv *.xxx *.yyy' e.g. might expand to 'mv' error: target is not a directory

UNIX newbie nasty tar gotcha:
   'tar -jcvf backup_my_stuff.tbz vitalfiles* criticaldir veryimportantstuff' # CORRECT
   'tar -cvf vitalfiles* criticaldir veryimportantstuff backup_my_stuff.tar' # GOTCHA! BAD.
The tar file name is in the wrong place in the second example. AUGH! The very first vital file (probably the most vital) is overwritten with tar file. A killer when you destroy some part of your work and IRONICALLY when you were being good and making a backup.

android studio project import could rename resources with invalid chars e.g. rename JPG jpg *.jpg  #YMMV(DOYFOR!(YIJMTAU(YIAJMTAU) :-) ))
I am sooooo funny sometimes.

. .         .    .        @           .       .         .                  .           .

android studio project import could rename resources with invalid chars e.g. rename s/JPG/jpg/ *.jpg   #|| rename JPG jpg *.jpg  #||find . -name *.jpg -exec e.t.c. #||$(ls *.jpg|)depending on your flavour of rename :-P

GNU/Linux Command-Line Tools Summary
Chapter 7. Working with the file-system
Mass Rename/copy/link Tools

mmv, rename(perl flavour) and bash scripting for f in *.xxx; do mv $f ${f##}; done

In Android-Studio.
Imported sdk/samples android-17/HoneycombGallery

After import build failed:
Execution failed for task ':app:mergeDebugResources'.
> /home/james/src/HoneycombGallery/app/src/main/res/drawable-nodpi/stargazer_droid.JPG: Error: Invalid file name: must contain only lowercase letters and digits ([a-z0-9_.])

Renaming *.JPG to *.jpg solved problem easy.
Should the import tool take care of renaming resources when importing projects?

If for some reason your project does not build, and you determine that
it is due to a bug or limitation of the Eclipse to Gradle importer,
please file a bug at with category

RELATED (but not the same) to this issue:
Issue 31: Resource file names generate invalid Java identifiers

No comments: