Grepping for project numbers

This script is so simple and helpful to me that I can’t believe I didn’t write it years ago. It fills a specific need of mine that it won’t be directly useful to anyone else, but it may inspire you to think about similar things that would save you time.

Here’s my problem. My company assigns a name and number to each of our projects. The names are not unique, but the numbers are, so knowing the project number is important when entering information and querying our company-wide databases. Unfortunately, I think of my projects in terms of names—either the name of the project itself or the name of the client I’m working for—rather than numbers. When I need a project number, I either:

  1. Search for the name on the company-wide database and then sift “by hand” through the returned results. This forces me to leave my office, as the company-wide database is not networked and is available on only one computer.
  2. Open my file cabinet and look for folders from that project. My folder labels have both the project name and number.
  3. Open a project list text file on my computer and search for the project. I’ll discuss the format of this file in a bit.

None of these options are very good. Option 1 is obviously the worst because it takes the most time. The other two are quicker, but still force me to take several steps—literally in the case of Option 2—to get the answer. A better solution would be to automate Option 3.

For over a decade, I’ve kept a file in my home directory that lists all of “my” projects, projects that I direct or work on. It’s a text file written in a very specific format so that various scripts can grab that information for writing standard (boilerplate) letters, addressing envelopes, etc. Each line of the file represents a single project, with the project information formatted like this:

Angel Industries Boiler|2997|Eugene Johnson|File no. 02-445-EAJ|angel.boiler|14

The fields, separated by a pipe (|) character, are:

The first four are self-explanatory. The subdirectory is the name of the folder where I keep all computer files associated with the project. The box number is the number of the file box in long-term storage where all the physical paperwork is stored after the project is closed. Fields that don’t have a value are left blank, but the five pipes are still there. For example, if I didn’t know the client’s project number and if the project was still active, the info would look like this:

Angel Industries Boiler|2997|Eugene Johnson||angel.boiler|

As new projects come in, I add new lines to the bottom of the file. I’ve named the file pl, and I keep it in my Dropbox folder1 for automatic syncing between my desktop and laptop computers.

What I’m looking for is a streamlined way to search this file. I don’t want to open the file, I don’t want to close the file, I don’t want to open a Terminal window and type in a command. I want the absolute minimum of user interaction.

What I’ve come up with is an AppleScript triggered by a keystroke combination via FastScripts. The AppleScript is called Project search.scpt and is kept in my ~/Library/Scripts folder where FastScripts can find it. I have it bound to the ⌃⌥⌘-\ keystroke combination, because the backslash is on the same key as the pipe, and the pipe reminds me of the field separators in the file.

Here’s the script:

 1:  -- Get the search term or cancel.
 2:  tell application "System Events"
 3:    activate
 4:    display dialog "Search term:" default answer "" buttons {"Cancel", "Search"} default button "Search" with title "Projects"
 5:  end tell
 6:  if button returned of the result is "Cancel" then
 7:    return
 8:  else
 9:    set term to text returned of the result
10:  end if
12:  -- Construct the grep and filter command.
13:  set cmd to "grep -i '" & term & "' ~/Dropbox/pl |  perl -pe 's/(\\|[^|]*){4}$/\\n/' | tail -r"
15:  -- Run the command and show the output.
16:  set foundProjects to do shell script cmd
17:  if foundProjects is "" then
18:    set foundProjects to "None"
19:  end if
20:  tell application "System Events"
21:    activate
22:    display dialog foundProjects buttons {"OK"} default button "OK" with title "Found projects"
23:  end tell

Update 11/12/09
I just realized I needed to wrap the display dialog commands in tell application blocks to force the dialogs to be the frontmost windows when the command is run.

The user interaction in Lines 1–7 and 17 is self-explanatory. When run, the script puts up this input window

and presents the results of the search like this

If the search term matches more than one project, a line for every matched project is shown.

The real work of the script is in the shell command constructed in Line 10. It first does a case-insensitive grep of the search term on the project list file. It then filters out the last four fields and their pipe characters through a Perl one-liner. I just want to see the project name and number so I can get the latter from the former. The doubled backslashes in the regular expression are there to keep AppleScript from interpreting the escapes before Perl has a chance to see them. Finally, the lines (if more than one matches the search term) are reversed via tail -r so the most recent project—the one I’m most likely to be searching for—is at the top.

I don’t think I can reduce the user interaction any further. Apart from typing in the search term, there’s just

As I said at the top, there’s no way this script can be used by anyone but me. But the idea of using scripting to automate repetitive and boring tasks is universal.


  1. How did I ever get along before Dropbox?