Avvio conciso delle app per Mac OS dalla riga di comando


22

Faccio una buona dose di lavoro nella riga di comando e mi ritrovo a definire molti alias del modulo:

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

C'è un modo per aggiungere magia in modo tale che la richiesta di "pippo" eseguibile usi automaticamente eseguibile /Applications/Foo.app/Contents/MacOS/Foo? Questo è su OS X 10.6.

(Sono consapevole che potrei farlo open foo.pdf, ma Skim non è il lettore PDF predefinito e vorrei una soluzione generale - in alcuni casi, non è appropriato impostare l'applicazione in questione come gestore predefinito per il file.)


22
Puoi open -a Skim foo.pdf.

1
@mankoff: bello, ho dimenticato che potresti usare -a per dire aperto che vuoi un'app dalla directory Applicazioni. dovresti cambiarlo in una risposta :)
Robert S Ciaccio,

@Reid: potresti modificare la tua domanda per includere una riga di comando di esempio che stai cercando di poter digitare?
Robert S Ciaccio,

@mankoff, il che significa che ha sicuramente bisogno di alias o estensione del completamento della scheda
Robert S Ciaccio

@Riesci a riscontrare problemi con la soluzione?

Risposte:


10

Finalmente ho capito: aggiungi questo al tuo .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 il seguente lavoro:

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

Modifica di Reid:

Ho implementato quanto sopra come uno script Python che crea script wrapper anziché alias. Dovrai inserire il ~/bin/mankoffmagictuo percorso. Se vuoi che gli involucri vengano aggiornati automaticamente, eseguilo 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()

"Grep -v iWork" è lì solo perché l'apostrofo in "iWork '09" sta rovinando le cose. Notare che se si memorizzano app altrove (~ / local / Applications) è sufficiente aggiungerlo al lscomando e funzionerà anche lì.

Ben fatto. mi piace che sia dinamico in modo da non finire con problemi di manutenzione come la pulizia di vecchi alias.
Robert S Ciaccio,

Grazie @mankoff! Ha un ottimo profumo - una volta che l'ho provato e funziona, segnerò la risposta accettata. Molto apprezzato.
Reid,

OK, questo funziona. Si interrompe sulle app con un apostrofo (e presumibilmente altri caratteri divertenti nel nome). Ho cercato la tua soluzione e ho fatto qualcosa di simile in Python, che posterò in un'altra risposta - anche se se non è l'etichetta giusta, sono felice di aggiungerlo invece alla tua risposta (o qualsiasi altra cosa).
Reid,

8

Non hai bisogno di niente di speciale, hai già la risposta. Provare:

open /Applications/Foo.app bar.pdf

in modifica

Alla luce dei commenti qui sotto, penso che la mia risposta sarebbe ancora relativamente simile ... Farei una funzione che si apre, fa un pushd a /Applications, chiama /usr/bin/open $appName.app $args, fa un popd e ritorna.

Faccio schifo allo scripting della shell ma qualcosa di simile al di sotto che copre casi speciali e ti fa usare praticamente la stessa sintassi di apple prevista per open. Mi piace mantenere il mio ambiente il più pulito possibile.

Sono sicuro che la sintassi proviene dallo spazio:

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
}

alla seconda modifica

Guardando il commento di @ mankoff sulla domanda originale, la maggior parte delle cose nella funzione sopra sarebbe probabilmente una perdita di tempo poiché potresti semplicemente usare open -a $appName. Quindi mankoff ha probabilmente la soluzione più semplice e dovrebbe cambiare il suo commento in una risposta;)


Penso che @Reid voglia un modo più breve senza creare manualmente tutti gli alias.

Ma non deve creare un alias nell'eseguibile unix se usa 'open' sul pacchetto .app. Ho avuto l'impressione che stesse creando alias perché pensava che l'unico modo per avviare un'app direttamente dalla riga di comando fosse andare fino in fondo alla directory di MacOS ed eseguire il file che è l'eseguibile "reale" all'interno di un'app. Quindi, in tal caso, un alias salverebbe almeno digitando i tre livelli extra di struttura di directory necessari per avviare l'app. Forse sto fraintendendo la sua domanda.
Robert S Ciaccio,

@calevara, grazie - @mankoff ha ragione; si tratta di lunghezza.
Reid,

3
Questo è un po 'un uso improprio della funzionalità di modifica. Se in seguito desideri proporre una seconda risposta, fai proprio questo. Non modificare la risposta originale, trasferendo sulle spalle i voti ricevuti sulla nuova idea.
Jeff Swensen,

1
Non sono d'accordo ... la risposta è ancora abbastanza simile perché userebbe la stessa sintassi. Non solo, ma se i votanti non gradiscono la nuova risposta, possono cambiare il loro voto perché la risposta è stata modificata. Questo è esattamente il motivo per cui puoi cambiare il tuo voto dopo le modifiche. È anche il motivo per cui ho messo "in modifica" in grassetto.
Robert S Ciaccio,

4

Ci sono due soluzioni a cui posso pensare:

Il modo più semplice : utilizzando il Info.plistfile in ciascuna Contentsdirectory .app , creare un indice del valore per le chiavi CFBundleExecutable. Quindi aggiungi un breve alias che chiama uno script (perl, python, qualunque cosa) con il nome di un eseguibile e gli argomenti che desideri passare.

Il tuo indice sarebbe costituito da coppie di nomi eseguibili e percorsi per tali eseguibili. Dovresti scrivere uno script programmato ricorrente per mantenerlo aggiornato.

Saresti in grado di chiamare:

f foo file.txt

dove f è un alias di uno script che controlla l'indice per un eseguibile denominato foo.

Tutto sommato, non c'è molto lavoro per ottenere la funzionalità che desideri.

Il modo più difficile - Estendi la tua shell per integrare la gestione del suo command_not_founderrore. Fondamentalmente implementeresti una method_missingfunzionalità in stile Ruby all'interno di qualunque shell tu stia usando. Quando è command_not_foundstato lanciato, il metodo controlla i nomi degli eseguibili delle applicazioni installate.


2

Applescript in soccorso:

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

Sostituisci il nome dell'applicazione con l'applicazione che desideri avviare e il gioco è fatto. Ovviamente puoi renderlo una funzione shell se necessario:

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

e usalo in questo modo:

f iTunes

Odio applecript, ma a volte è utile e credo che l'unico modo per indirizzare un'applicazione semplicemente per nome sulla riga di comando. Tutto il resto richiederà un percorso completo.


Non supporta il completamento con tabulazione. Richiede di ricordare esattamente i nomi delle app. Non vedo perché è richiesto AppleScript (specialmente se lo odi) se lo script della shell può fare tutto.

1
Non ho mai capito che open -a potesse essere usato senza un nome di file come argomento. E utilizzo open sin da NextStep a volte nei primi anni '90! Ti preghiamo di inviarlo come risposta per consentirci di votare. Quindi sì, la risposta corretta è usare 'open -a <nome applicazione>'
eric
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.