16 Feb

Making shell scripts more user friendly

We were recently asked whether it was possible to copy all the files that contain some variable text from Folder A into Folder B as part of an Automator workflow on Mac OS X.

Our solution demonstrated a nice way of using Automator as a way to gather information from a user and pass it to a shell script. It’s handy because many users feel intimidated by the Terminal, but are happy to run an Automator action. Here’s what we did…

First, let’s assume that we have two folders on our desktop. One is called “Source” and the other called “Dest”. If we wanted to copy all files whose name contains “Xxx” from Source to Dest then we could fire up the Terminal and do:

find ~/Desktop/Source -type f -name "*Xxx*" -exec cp "{}" ~/Desktop/Dest \;

The “*Xxx*” bit is where we tell the find command that we’re interested in files whose name “Xxx” with any text before or after it. You might want to read up on other options the find command has if you’re not familiar with it – it can be really useful.

However, we don’t want “Xxx”, we want the user to be able to decide what text to search for. So, let’s set up an Automator workflow and add an action to get some that text from the user…

Ask for text

Hopefully that’s straight forward. Next, we add a “Run Shell Script” action:

Run shell script

If you feel like copying and pasting, then the code is:

for f in "$@"
do
find ~/Desktop/Source -type f -name "*$f*" -exec cp "{}" ~/Desktop/Dest \;
done

That’s probably a little less straight forward! So let’s look at it a bit more closely. First, note that “pass input” is set to “as arguments”. This means that the output of the previous action is passed to our shell script as a special variable called $@.

The variable $@ could theoretically be a list, so we use a for loop to go through each item. Odds are that it’ll only ever be one item, but at least this way it’ll still work if one day it is a list. Our for loop goes through the $@ list an item at a time and executes the code between “do” and “done” once for each item in that list (the item is in a variable called $f). The code being executed should be familiar as the find command from earlier, but with $f as the search string instead of “Xxx”

So, if you run the workflow now you should be prompted to enter some text. Your source folder should be scanned for files whose name contains the text you entered, and any matching files copied to the destination folder.

You can run the workflow as it is, or save it as an Application if you prefer. Hopefully users will find this a more user friendly way of passing parameters to a shell script and exceuting it than using the Terminal.