Domanda

Faccio una buona dose di lavoro nella riga di comando, e mi ritrovo la definizione di un sacco di alias di forma:

alias skim='/Applications/Skim.app/Contents/MacOS/Skim'

C'è un modo per aggiungere magia tale che chiedere "pippo" eseguibile utilizza automaticamente /Applications/Foo.app/Contents/MacOS/Foo eseguibile? Questo è su OS X 10.6.

(Mi rendo conto che avrei potuto fare open foo.pdf, ma Skim non è il lettore PDF predefinito, e mi piacerebbe una soluzione generale - in alcuni casi, non è opportuno impostare l'applicazione in questione come il gestore predefinito per il file).

È stato utile?

Soluzione

Finalmente ho capito: Aggiungi questo al vostro .bash_profile

function foomagick() {
    rm -f ~/.foomagick.tmp
    ls /Applications/ | grep "\.app" | grep -v iWork | while read APP; do
        # clean it up                                                           
        a=`echo $APP | sed s/\ //g`;
        a=`echo $a | sed s/\'//g`;
        echo alias ${a%.*}="'open -a \"${APP%.*}\"'" >> ~/.foomagick.tmp
    done
    source ~/.foomagick.tmp
    rm ~/.foomagick.tmp  
}
foomagick()

Ora i seguenti lavori:

Skim # open Skim.app
Skim foo.pdf
FireFox http://google.com
FireFox google.com # ERROR. Looks for local file.

Modifica da Reid:

I implementato quanto sopra come uno script Python che fa involucro script invece di alias. Avrete bisogno di mettere ~/bin/mankoffmagic nel tuo percorso. Se si desidera che i wrapper per essere aggiornati automaticamente, eseguire regolarmente da cron o somesuch.

#!/usr/bin/python
#
# This script automagically updates a set of wrapper shell scripts in
# ~/bin/mankoffmagic which call Mac apps installed in /Applications.
#
# Inspired by mankoff's shell alias posted on apple.stackexchange.com; see:
# http://apple.stackexchange.com/questions/4240/concisely-starting-mac-os-apps-from-the-command-line/4257#4257
#
# Notes/Bugs:
#
# 1. Does not follow symlinks (aliases?)
#
# 2. Assumes that application names do not contain double-quotes.
#
# 3. Not very smart about finding the actual binary (it guesses). This is
# wrong sometimes, e.g. Firefox. Probably a deeper understanding of the app
# package structure would fix this.

import copy
import glob
import os
import os.path
import re

BINDIR = os.path.expandvars("$HOME/bin/mankoffmagic")
APP_RE = re.compile(r'(.*)\.app$')
STRIP_RE = re.compile(r'[\W_]+')

def main():
   # We aggressively delete everything already in BINDIR, to save the trouble
   # of analyzing what should stay
   for f in glob.glob("%s/*" % BINDIR):
      os.unlink(f)

   # Walk /Applications and create a wrapper shell script for each .app dir
   for (root, dirs, files) in os.walk("/Applications"):
      dirs_real = copy.copy(dirs)  # so we can manipulate dirs while looping
      for d in dirs_real:
         #print "checking %s" % os.path.join(root, d)
         m = APP_RE.search(d)
         if (m is not None):
            #print "Found " + m.group()
            dirs.remove(d)  # no need to recurse into app
            create_script(root, d, m.group(1))

def create_script(path, appdir, appname):
   # remove non-alphanumerics and downcase it
   wrapper = STRIP_RE.sub('', appname).lower()
   wrapper = os.path.join(BINDIR, wrapper)
   fp = open(wrapper, "w")
   # Twiddle the comments in the script depending on whether you want to
   # invoke the binary or use "open" -- the former lets you use any
   # command-line args, while the latter is more Mac-like (app puts itself in
   # the front, etc.)
   fp.write("""
#!/bin/sh
exec "%s/%s/Contents/MacOS/%s" "$@"
#open -a "%s" "$@"
""" % (path, appdir, appname, appname))
   fp.close()
   os.chmod(wrapper, 0700)


if (__name__ == "__main__"):
   main()

Altri suggerimenti

You don't need anything fancy, you already have the answer. Try:

open /Applications/Foo.app bar.pdf

on edit

In light of the comments below, I think my answer would still be relatively similar... I would make a function that overrides open, does a pushd to /Applications, calls /usr/bin/open $appName.app $args, does a popd and returns.

I suck at shell scripting but something like below which covers special cases and keeps you using pretty much the same syntax as apple provided for open. I like to keep my environment as clean as possible.

I'm sure the syntax is from outer space:

function open($appName, $args)
{
    #if we are calling open without a path like /Applications/TextEdit.app AND
    #    $appName ends in '.app'
    if (!hasParent($appName) && isApp($appName))
    {
        pushd /Applications
        /usr/bin/open ${appName}.app $args &
        popd
        return
    }
    #otherwise, use open as normal
    /usr/bin/open $appName $args
    return
}

on second edit

looking @mankoff's comment on the original question, most of the stuff in the above function would probably be a waste of time since you could just use open -a $appName. So mankoff probably has the easiest solution and should change his comment to an answer ;)

There are two solutions that I can think of:

The easier way - Using the Info.plist file in each .app Contents directory, create an index of the value for the keys CFBundleExecutable. Then add a short alias that calls a script (perl, python, whatever) with the name of an executable and the arguments you'd like to pass.

Your index would be pairs of executable names and paths to those executables. You'd have to write a recurring scheduled script to keep this updated.

You'd end up being able to call:

f foo file.txt

where f is an alias to a script that checks your index for an executable named foo.

All in all, not a lot of work to get the functionality you'd like.

The harder way - Extend your shell to supplement the handling of its command_not_found error. Essentially you would implement a Ruby style method_missing functionality within whatever shell you're using. When command_not_found was thrown, your method would check the executable names of your installed Applications.

Applescript to the rescue:

osascript -e 'tell application "iTunes"' -e "activate" -e 'end tell'

Replace the name of the application with the application you want to start and you're done. You can of course make it a shell function if needed:

function f() {
    osascript <<EOF
tell application "$1"
  activate
end tell
EOF
}

and use it that way:

f iTunes

I hate applescript, but it is useful sometimes, and I believe the only way to address an application simply by name on the command line. Everything else will require a full path.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a apple.stackexchange
scroll top