Categories
Command Line (CLI) Using Linux

Cygwin rename command help

Rename files in cygwin, overcoming a limitation

Cygwin is a Linux-like environment for Windows.  It comes in handy when you’re at work, or at home, and your only operating system happens to be Microsoft Windows.  Cygwin allows you to issue Linux commands in a console in Microsoft Windows.  I find it easier to use than the DOS CMD prompt when I’m using a Windows OS.  It’s a great way to get things done quicker, and can be scripted—in a similar environment to a Linux Terminal.

So, let’s say you’re seasoned in the Linux shell.  You’re now at work, using Cygwin, and you want to rename a lot of files based on their name matching a pattern of letters or numbers or both.  This is where cygwin has some trouble.

By default, cygwin does not come with rename ability.  The package util-linux is required.

Cygwin’s rename command renames files if you tell it the exact name of your target file.  This is the same as the mv command. I’m no Cygwin expert, but this is the experience I’ve had.

In Linux, you can rename files using wildcards or pattern matches.  Cygwin’s rename command cannot seem to handle regexes in the same way.  I’ve tried a fair amount of googling to see why this command has limited behavior in cygwin.  I haven’t found a usable solution or add-on to cygwin to overcome this limitation.

So, here’s a shell script that uses sed, mv, and find to overcome the limitation.  I was unable to attach it, so I copied and pasted it below.

Please understand and accept the following disclaimer:  YOU MAY USE & MODIFY THE SCRIPT.  AUTHOR ASSUMES ZERO LIABILITY.  SCRIPT INTENDED FOR USE IN CYGWIN WITHIN A WINDOWS OS. SCRIPT COMES WITH NO WARRANTY, USE AT YOUR OWN RISK. Thanks.

#!/bin/sh
# cygrename : A Program to overcome limitation of cygwin's "rename" function.
# Author: Adam Teller
#
# Cygwin's "rename" doesn't work same way as *Nix "rename"
# because it cannot use wildcards. So, what can we do?
## Get the basename of the file if it matches search pattern.
## If 4th argument is set, change file to that suffix.
## else, match pattern within file name and keep same suffix
#
## Arguments: [search pattern] [replace pattern] [in suffix] [to new suffix]

LIST1=$(find . -type f -name "*${1}*\.${3}")
if [ -z "${LIST1}" ];
 then
   printf "Did not find any file matches, program will exit\n"
 exit 1
fi

for found in $LIST1;
 do
   MATCHEDFILE=$(basename $found);
   NEWFILENAME=$(echo $MATCHEDFILE | sed -e "s/${1}/${2}/");
   NEWFILENAMENOEXTENSION=$(echo $NEWFILENAME | sed -r "s/\.${3}//");

   ## TEST if $4 has been set, it means want a new file suffix
   if [ -z "${4}" ];
     then
       printf "$MATCHEDFILE :to be renamed as: $NEWFILENAME for files of type ${3}\n";
       mv $MATCHEDFILE $NEWFILENAME;
     else
       printf "${NEWFILENAMENOEXTENSION}.${3} will get $4 as its suffix, ";
       printf "and be renamed to ${NEWFILENAMENOEXTENSION}.${4} \n";
       mv $MATCHEDFILE "${NEWFILENAMENOEXTENSION}.${4}"
  fi
 done

 exit 0

Ok, I’ve copied the script and saved it, how do I use it?

  • Run your script from the same directory that has the files that you want to rename. I’ve named my copy “cygrename” (short for “cygwin rename”) but you may save your file with another name if you wish.  Make sure your script is executable. Use the cd command to get to the correct directory.
  • It accepts 3 or 4 command line arguments.
  • Invoke it in the shell using sh cygrename “what-to-find” “replace-it-with” “file extension” “new file extension” (optional).
  • The “file extension” argument does not include the dot (.), just use letters such as txt or doc or gif.
  • 3 arguments is the minimum and I’ve omitted the argument counting, you may however wish to add it into your program so that the 3 argument minimum is enforced.
  • In the even that the program does not find a match, the program exits.
  • The script uses the find command to look for files matching your pattern.  The result of a “find” usually includes the path information.  This is why we use the basename directive.  We just want the actual file name.  For example, a call to find might result in “./file1.pdf” and what we really want to use is “file1.pdf”
  • If the optional 4th argument is used, it indicates a desire to change the file suffix.  Otherwise, you can rename files and keep the file suffix as is.

Here’s a way to store & use the script.  This script is yours to use & modify as you wish.

  1. Store the script (assuming you’ve named it cygrename) in the “bin” folder in your user’s home folder.  In a windows environment, this is usually C:\cygwin\home\userName\bin.  When you first see this folder, it should be empty.  There is a cygwin “system” bin that will be full of executable files. THIS IS NOT what you’re looking for. You are looking for your user’s bin folder, which will be empty until you start putting files into it.
  2. Once you’ve used the cd command to get to the folder where the target files reside, you can invoke the script.  The script can be more easily invoked if you change the PATH variable in Cygwin.  Find instructions here.  Adding your user’s bin directory to your search PATH is recommended because it will allow you to call the script just by its filename, and won’t require the entire path name of the script.
  3. In this example, for simplicity, I’m assuming you have several files in the same “bin” directory as the script you have saved.  You have 4 image files named “picture1.jpg” “picture2.jpg” “picture3.jpg” and “picture4.jpg” .  You want to change “picture” to “img” and keep the files as *jpg  -From within the “bin”directory, Call the script as sh cygrename “picture” “img” “jpg”
  4. Your 4 jpg files should now be named “img1.jpg”, “img2.jpg” and etc.
  5. If (based on previous example) you wanted to change some web files (html) AND their file suffix, you could call the script as sh cygrename “website” “site” “htm” “html” and it would rename files such as “websiteLocation.htm” to “siteLocation.html” because you used the optional 4th argument.
  6. Please be aware that simply changing a file extension DOES NOT CONVERT a file.  What I mean is that if you change a file suffix of “img2.jpg” to “img2.gif” you are not converting to the gif file type.  The file becomes a jpg file named with an incorrect suffix.  This is not recommended.  However, changing an extension from .htm to .html is ok because it is a text-based file.  Image files, office suite files, and multimedia files should only have their suffix changed by using another application to convert the files.
Categories
Command Line (CLI) Using Linux

The linux find command

Using the find command to find and move files

Today I’d like to discuss one of my favorite shell commands: find.
find is awesome.  It locates files on your unix/linux system by using options and criteria.

Many of us are familiar with using the Microsoft Windows “Search Tool” in XP to Find Files or Folders, files by date, etc.  Finding a file this way involves populating text fields, drop-down menus, and (possibly) date-range selectors to find the files you’re looking for.

In unix and linux, the find command is used like this:

find [directory to search] [options] [actions]

Here’s a find command example.  Let’s say we want to find .mp3 files within your “Music” folder (/home/yourName/Music).  For this example, let’s pretend that you have the following files: song1.mp3, song1.wav, song2.mp3, song2.wav, song3.mp3, and song3.wav.

To find files in the Music directory, the command is: [don’t type the dollar sign- it’s the prompt, start typing at the word “find”.]

$ find Music/ -type f [press ENTER]
Music/song1.mp3
Music/song1.wav
Music/song2.mp3
Music/song2.wav
Music/song3.mp3
Music/song3.wav

We used the “-type f” option to find a regular file and not a directory.  The output (above) shows that we have media files (mp3 and wav) in the Music folder.  Remember we’re not interested in listing files so much as performing a ‘find’ on them.

On a Linux system you can use a GUI program to find files, but you can find them faster using the find command.  With its many options, find’s power is in its flexibility.  Flexibility to do what??? Finding files is finding files, right? Yes, I suppose so.

But what if you wanted to perform an action on files that you find? In Windows you’d have to first find them, navigate to them, and then (possibly) perform actions on them one file at a time.  While the steps are few, they can be manual and tedious, thus begging for a shortcut.

Let’s take our example a step further.  Let’s filter the command to only find ‘mp3’ files.  We’ll add the “-name” option to search wildcard patterns for files ending in mp3.

$ find Music/ -type f -name "*mp3"
Music/song1.mp3
Music/song2.mp3
Music/song3.mp3

If you wanted to find only the .wav files, then you’d change *mp3 to *wav.  Now let’s use find to move files to another folder.  For the sake of neatness, let’s create 2 sub-folders (also known as sub-directories) to hold mp3 files and a separate sub-folder for wav files.

To create a new directory use mkdir [folderPath].  If you do not specify a folder path, the shell creates the directory within the current working folder.  More on “current working folder” later.  For now, let’s assume that you’re in the “home/yourName” folder.

Creating folders “Music/mp3” and “Music/wav” requires 2 identical commands.  However, you can create 2 sub-directories in the “Music” folder with the command below.

mkdir Music/{mp3,wav}

Brackets tell the shell to expect a sequence of characters.  The comma separates each new directory.  This is the same as issuing mkdir Music/mp3 and mkdir Music/wav.

With the sub-folders created, we have a neater storage arrangement for our music files.  But we’re not done yet.  Remember that our “Music” folder currently stores both mp3 and wav files.  Let’s move each type into their respective sub-directory.  To make this happen we add an action onto our command known as “-exec” (followed by the “command terminator” \;) and the mv command to move the files as seen in the example below:

mv fileOldLocation fileNewLocation

Note: mv also renames files and can overwrite them—so use caution because mv actions cannot be undone.  For safety, use mv -i which is interactive in the event of a possible naming conflict or unintentional overwrite—it may save you anguish.

We then add brackets {}, BUT brackets behave differently in this context.  When brackets are part of -exec they represent each found file.  Also, when moving a file to another directory, put the trailing slash / on the target directory name.

To move the mp3 files from directory level “Music” to “Music/mp3” issue this command:

$ find Music/ -type f -name "*mp3" -exec mv -i {} Music/mp3/ \;

Since there weren’t any files in Music/mp3 we didn’t get any warnings from mv -i
Result: mp3 files moved from /home/yourName/Music to /home/yourName/Music/mp3/

To check it, you can use the ls command in the shell to “list” files in a given directory

$ ls Music/mp3/
song1.mp3  song2.mp3  song3.mp3

To move the wav files from directory level “Music” to “Music/wav” issue this command:

$ find Music/ -type f -name "*wav" -exec mv -i {} Music/wav/ \;
$ ls Music/wav/
 song1.wav  song2.wav  song3.wav

Summary

  • find (and its options) allow you to find files and perform actions on the found items
  • mkdir allows you to create new directories
  • ls lists files (and directories, subdirectories) within folder(s)
  • mv moves or renames files