geohar has asked for the wisdom of the Perl Monks concerning the following question:

Ok, this is a bit of an odd one but it's been bugging me for days. I'm using perl as part of a filter for listing all running applications. The point is to be able to use the list returned as a completion for a command in tcsh... Ok. So this is really fairly obscure.

I'm running OSX, so some explanation of how applications show up in ps listings may be required. Using ps -axwwo command= I'll get a list of processes including those without controlling terminals, and doesn't width-limit the result and only prints the command path + arguments.

As well as the applications which are running, there's also going to be a fair few other processes. I don't want those in the list.

The rules for how an application looks in the ps listing:

1. All applications have XXX.app/Contents/ in their path, the actual executable being at something like somepath/XXX.app/Contents/MacOS/XXX Or perhaps somepath/XXX.app/Contents/MacOSClassic/XXX. Anyhow, all applications have XXX.app/Contents/ in their path.

2. Applications may infact be nested (helper apps etc). So may appear as somepath/XXX.app/Contents/Resources/Helper.app/Contents/MacOS/Helper which kinda confuses things somewhat, as the running app is actually Helper, not XXX.

3. In the ps listing you have often a postfixed "-psn=101010" indicating the psn of the application.

4. Incidentally application names may contain spaces ;(

I want a listing consisting of the running applications, only. In the form

A.app B.app C.app

etc. even when C.app may be inside D.app's bundle folder.

Yeah, this is very esoteric.

So currently, I have the following line which I execute in tcsh.

/bin/ps -axwwo command= | grep '\.ap\{2\}/Contents' | perl -p -e 's|^/(([^/]+)+/)+(.+\.app)/.*$|$3|'

Can anyone do better? I'm looking for a one-liner. I'd love to fold the grep into the perl, but it complicates processes finding themselves, and I couldn't see how to do it as a perl filter...

Note that the use of the grep and it's bizarre construction means it doesn't match itself or the perl filter.

Replies are listed 'Best First'.
Re: The simplest (perl) filter for the job
by ccn (Vicar) on Oct 15, 2004 at 09:30 UTC

    /bin/ps -axwwo command= | perl -pe '$_ = /\.app\/Contents/ && m{([^/]+ +\.app)/} ? $1 : ""'
    Update: shorten
      Excellent. Though a couple of mods

      /bin/ps -axwwo command= | perl -pe '$_="" if ! /\.app\/Contents/ ; $_ += m{([^/]+\.app)/} ? "$1\n" : ""'

      The expression order needs to be swapped as the previous order stripped off the /Contents before it can be matched by the second expression. Also a space after the '!' prevents tcsh trying to history-expand the search... Thanks

      Yeah, that's nice. Out of interest, is the match guaranteed to return the last match (as in the case of an app in an app) ? It seems to, but I wasn't sure...
        Damn, replying to my own post. The + or * operator seems to leave the bound backref as the last match out of all the repetitions...
Re: The simplest (perl) filter for the job
by Roger (Parson) on Oct 15, 2004 at 12:09 UTC
    Try to use a regular expression to capture all occurances of *.app into an anonymous list, an then retrieve the last occurance of *.app in the list:
    +(/(\w+.app)/g)[-1]