Finder and glob

April 14, 2008

I’ve found a really nice, well documented, AppleScript application that makes for easy work to use Unix path pattern expansion (glob) syntax along with Finder. This is the utility you want around when you need to select a specific set of files within Finder, and command-clicking just isn’t going to cut it.

For instance, when you need to select files with a unique patterns such as: files that contain the string “test” (anywhere within the filename), or only those files where the name contains “test” and the extension is “rb”.

The application I am referring to is lselect, and here are a few examples:

All files with “test” in the name and the extension “rb” will be selected:

Easy enough, however, lselect also allows you to add to the current list of selected files, as shown below where I ask for all files with a “C” extension (notice the button ‘Add Matches’):

The resulting list of files is shown below:

The source code for lselect is shown below (it looks rather long, however, much of the listing is comment blocks):

Script Editor Click here to paste the code below into the Script Editor

(*
  lselect 1.1 by Jim DeVona

http://anoved.net/lselect.html

  1.0: 1 November 2006
  1.1: 18 December 2006 (somewhat improved Column view behavior)

  Select files in the current Finder folder using shell glob syntax.
  When invoked, the user will be prompted to supply a glob pattern.
  The "ls" command line utility is used to determine which files match
  the pattern, and then they are selected.

  Suggested installation location:
    ~/Library/Scripts/Applications/Finder/lselect.scpt

  The script can be invoked with the standard Mac OS X Script Menu,
  but I've found FastScripts (http://www.red-sweater.com/fastscripts/)
  to be a preferable alternative, primarily because of the ease with
  which reliable keyboard bindings can be assigned. I use Command-G.

  Issues:
    - If the last match is a directory and the current view type is
      Column, other matches will not end up selected (they appear
      to lose selection when the Finder come to rest on and reveals the
      contents of the last directory). I don't know how to prevent this.
    - Spaces must be escaped to match properly: "iTunes\ Music"
    - Performance is poor with hundreds of matches; see notes below

  Wishes:
    - Select sub-matches within current selection
    - Select matches on desktop instead of in "Desktop" window
    - Support patterns like "../" (subfolder patterns work, but not parent)
*)

tell application "Finder"

  (*
    Determine the present working directory as alias and POSIX path.
    If the insertion location is not a folder, use its parent. This is the
    case when a file is selected in Column view (otherwise, file selections
    do not seem to be treated as the insertion location).
  *)
  set pwdAlias to insertion location as alias
  if not (exists folder pwdAlias) then
    set pwdAlias to (container of pwdAlias) as alias
  end if
  set pwd to POSIX path of pwdAlias

  (*
    Ask the user what to select. Dialog time out is equivalent to cancellation.
    The default "Select Matches" option clears the current Finder selection,
    whereas "Add Matches" leaves it intact. Clearing the selection is not done
    in Column view if the displayed folder is the only thing selected.
  *)
  set dr to display dialog "Glob pattern:" default answer ¬
    "" buttons {"Cancel", "Add Matches", "Select Matches"} ¬
    default button 3 cancel button 1 with title pwd giving up after 60
  if button returned of dr is equal to "" then
    return
  else if button returned of dr is equal to "Select Matches" then
    try
      -- do not clear selection if the only thing selected is the focal folder
      if selection as alias is not equal to pwdAlias then select {}
    on error
      -- more than one thing already selected
      select {}
    end try
  end if

  (*
    Initialize list of selected files. Generally identical to selection returned
    by Finder, except the present working directory should not be included,
    which is initially selected in some Column view circumstances (see above).
    This is a little clumsy; selection state is vaguely defined in Column view.
  *)
  set selectables to selection
  try
    if selection as alias is equal to pwdAlias then set selectables to {}
  end try

  (*
    Get the glob pattern given by the user.
    We treat a blank pattern as cancellation (use * to select everything).
    Alternatively, omit this conditional to select the containing folder;
    this ought to be the default behavior once "../" issues are ironed out.
  *)
  set query to text returned of dr
  if query = "" then return

  (*
    Ask ls for a listing of files that match the given pattern.
    From the ls man page:
      -d Directories are listed as plain files (not searched recursively).
    If nothing matches the query, ls will return an error; just stop.
  *)
  try
    tell me to set matches to do shell script ("/bin/ls -d " & quoted form of pwd & query)
  on error
    return
  end try

  (*
    Parse each line of the response from ls as the path to a match.
    The visibility test is twofold: the "info for" test throws an error on
    Icon^M (the full name doesn't survive all translations and transmissions).
    This try-info-for-visibilty test is the main bottleneck;
    for faster handling of many matches (100s), replace this
    repeat body with "set end of selectables to matchpath as POSIX file"
  *)
  repeat with matchpath in paragraphs of matches
    set posixmatch to matchpath as POSIX file
    try
      set fileinfo to info for posixmatch without size
      if visible of fileinfo then set end of selectables to posixmatch
    end try
  end repeat

  (*
    Conclude by selecting the results.
    The "try" protects against cases we don't [yet] handle,
    such as certain "../" path traversals and anything else that may come up.
    If the last item of selectables is a directory and we're using
    Column view, other items may not end up selected.
  *)
  try
    select every item of selectables
  on error errMsg number errNum
    display alert "Could not make selection (" & errNum & "):" message errMsg as critical
    return
  end try
end tell

Here is brief list of glob syntax you can try with lselect:

? Match any one character.
* Match any sequence of zero or more characters.
[abc] Match any one character in abc. A range of characters may be specified as a-z, or 0-9.
[^abc] Match any one character not in abc.
{a,b,c} Matches any of the strings a, b, or c, which may consist of more than one character each.

lselect shows a good use of AppleScript, is well documented and it’s handy…all good things.

2 comments

Hello
this is a great script
How could I rewrite it to recursively search through folders?

Vic.

by prijker on Jun 9, 2008 at 6:34 am. Reply #

Hi prijker

Unfortunately this is not possible due to a limitation of the Finder’s select command.
This limitation has existed for a while and at the time of 10.5.7 is still there.

It is easy to modify the script to find all the files recursively as it just means modifying the shell script used, but it is not possible to tell the Finder to select all found matches within the same window in list view. The way the select command works at the moment is that it will open a Finder window for each new base path in the matches list and select the file in this opened window.

There are some Finder properties in its dictionary right now (completely expanded, expandable) and one command (expand) which deal with list and outline views but these are disabled. Once they are enabled they could theoretically be used to work around this issue by means of checking the properties and looping through all expanded folders in a list view and then calling select on a new match on each loop round.

cheers,

Andre

PS: I know this question is a year old :P

by Andre on Jun 25, 2009 at 5:00 pm. Reply #

Post a comment:

Required.

Required. Not published.