FROM: UNIX COMMAND LINE WORKSHOP
SKILL LEVEL: AGILE
One of the great advantages of the UNIX cli is the ability to write commands that can perform multiple actions without manual imput. This is automation. It can be further extended by chaning together many commands and logging the output, as a task report for the human operator to check.
We’ll explore this here, working with a folder of images as an example, that need to be renamed.
Copying multiple files to a renamed backup
Assume I have a folder /home/julian/images/screenshots with hundreds of PNG files with unweildy names. I want to strip the redundant “Screenshot” from the file name in one motion:
julian@ce:~/images/screenshots$ ls -lh total 401.6M -rwxr----- 1 julian julian 103K Apr 18 14:39 Screenshot_2013-07-25-16-29-56.png -rwxr----- 1 julian julian 333K Apr 18 14:39 Screenshot_2013-07-25-16-22-44.png -rwxr----- 1 julian julian 142K Apr 18 14:39 Screenshot_2013-10-10-23-36-44.png -rwxr----- 1 julian julian 226K Apr 18 14:39 Screenshot_2013-12-05-17-03-56.png ...
First I’m going to chain together a few commands to prepare using the shell ‘;’ separator.
I move up a level with cd, create a new folder to copy my renamed files into with mkdir and check my work with ls:
julian@ce:~/images/screenshots$ cd .. ; mkdir screenshots_renamed ; ls screenshots screenshots_renamed
Now I can write my command to rename the files, removing the “Screenshot” and copying the new files into my screenshots_renamed folder.
- Move up a level with cd
- Open a ‘for loop’, creating a variable $old from each file output by ls
- Create a variable $new from output of echoing $old to sed, replacing “Screenshot_” with nothing
- Copy $old to our $new filename into our***screenshots_renamed*** folder.
julian@ce:~/images$ cd screenshots julian@ce:~/images$ for old in $(ls .); do new=$(echo $old | sed \ 's/Screenshot_//') ; cp $old ../screenshots_renamed/$new; done
Note the use of the ‘’ special shell character in the above commands. It allows us to line break without breaking the command itself.
Check if our command worked:
julian@ce:~/images$ ls -lh ../screenshots_renamed total 401.6M -rwxr----- 1 julian julian 796K Apr 18 15:15 2012-07-30-00-15-29.png -rwxr----- 1 julian julian 98K Apr 18 15:15 2013-05-21-21-36-29.png -rwxr----- 1 julian julian 243K Apr 18 15:15 2013-07-25-16-22-26.png -rwxr----- 1 julian julian 333K Apr 18 15:15 2013-07-25-16-22-44.png ...
This can be all put into a script for use later. Here is an example script that use input variables and some testing (using if statements) to be sure we have what we need to perform the substution. Save it out as rename.sh and use chmod +x rename.sh to make it executable.
See the comments for a breakdown of how it works.
#!/bin/bash # Simple script to renames files in the current directory. # Takes a directory and two strings as input arguments, denoting the replacement. # Uses conditionals (if statements), shell variables, mkdir echo, sed and cp. HELP="\n ************************************************\n USAGE: ./rename.sh <directory> <original> <new>\n Renames files in a given directory\n Takes directory, text to find and text to \n replace as input arguments\n ************************************************\n" # First test we have all the input variables we need if [ "$1" ] && [ "$2" ] && [ "$3" ] then # Test that our source directory exists if [ -d $1 ] then DIR=$1 # Make new variable, appending "_renamed" to $DIR input argument NEWDIR=$DIR"_renamed" # Make our new directory mkdir $NEWDIR else echo "The source directory doesn't seem to exist. Quitting..." exit fi # Perform substitution using input arguments $2 $3 and copy to $NEWDIR # Note use of double-quotes rather than single in our sed expression. # This allows us to work with variables in the expression. for OLD in $(ls $DIR); do NEW=$(echo $OLD | sed "s/$2/$3/"); cp $DIR/$OLD $NEWDIR/$NEW; done echo "Performed substitution: " # List the results ls -lh $NEWDIR else # If we don't have the expected input arguments, echo $HELP echo $HELP fi