24 votes

Démarrage concis des applications Mac OS à partir de la ligne de commande

Je travaille beaucoup en ligne de commande, et je me retrouve à définir beaucoup d'alias de ce type :

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

Y a-t-il un moyen d'ajouter une magie telle que demander l'exécutable "foo" utilise automatiquement l'exécutable /Applications/Foo.app/Contents/MacOS/Foo ? Ceci est sous OS X 10.6.

(Je suis conscient que je pourrais faire open foo.pdf mais Skim n'est pas le lecteur PDF par défaut, et j'aimerais une solution générale - dans certains cas, il n'est pas approprié de définir l'application en question comme le gestionnaire par défaut du fichier).

23 votes

Vous pouvez open -a Skim foo.pdf .

1 votes

@mankoff : bien, j'ai oublié que vous pouviez utiliser -a pour dire à open que vous voulez une application du répertoire des applications. vous devriez changer cela en réponse :)

0 votes

@Reid : pourriez-vous modifier votre question pour inclure un exemple de ligne de commande que vous cherchez à pouvoir taper ?

10voto

J'ai enfin compris : Ajoutez ceci à votre .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()

Maintenant, le travail suivant :

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

Editer par Reid :

J'ai implémenté ce qui précède comme un script Python qui fait des script enveloppants au lieu d'alias. Vous aurez besoin de mettre ~/bin/mankoffmagic sur votre chemin. Si vous voulez que les wrappers soient mis à jour automatiquement, exécutez-le régulièrement depuis cron ou autre.

#!/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()

0 votes

Le "grep -v iWork" est là simplement parce que l'apostrophe dans "iWork '09" perturbe les choses. Notez que si vous stockez des applications ailleurs (~/local/Applications), il suffit d'ajouter cette information à l'adresse de l'utilisateur. ls et cela fonctionnera là aussi.

0 votes

J'aime bien que ce soit dynamique, ce qui évite les problèmes de maintenance comme le nettoyage des anciens alias.

0 votes

Merci @mankoff ! Cela sent bon - dès que je l'aurai testé et que cela fonctionnera, je marquerai la réponse comme acceptée. Merci beaucoup.

8voto

Shawn Points 8120

Vous n'avez besoin de rien d'extraordinaire, vous avez déjà la réponse. Essayez :

open /Applications/Foo.app bar.pdf

sur le montage

À la lumière des commentaires ci-dessous, je pense que ma réponse serait encore relativement similaire... Je ferais une fonction qui remplace open, qui fait un pushd vers /Applications appels /usr/bin/open $appName.app $args fait un popd et revient.

Je suis nul en script shell mais quelque chose comme ci-dessous qui couvre les cas spéciaux et vous permet d'utiliser à peu près la même syntaxe que celle fournie par apple pour open. J'aime garder mon environnement aussi propre que possible.

Je suis sûr que la syntaxe vient de l'espace :

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
}

en deuxième édition

En regardant le commentaire de @mankoff sur la question originale, la plupart des choses dans la fonction ci-dessus seraient probablement une perte de temps puisque vous pourriez simplement utiliser open -a $appName . Donc mankoff a probablement la solution la plus simple et devrait changer son commentaire en réponse ;)

0 votes

Je pense que @Reid veut un moyen plus court sans créer manuellement tous les alias.

0 votes

Mais il n'a pas besoin de créer un alias vers l'exécutable unix s'il utilise 'open' sur le paquet .app. J'ai eu l'impression qu'il créait des alias parce qu'il pensait que la seule façon de lancer une application directement depuis la ligne de commande était d'aller jusqu'au répertoire MacOS et d'exécuter le fichier qui est le "vrai" exécutable à l'intérieur d'une application. Donc, dans ce cas, un alias éviterait au moins de taper les trois niveaux supplémentaires de structure de répertoire dont vous auriez besoin pour lancer l'application. Peut-être ai-je mal compris sa question.

0 votes

@calevara, merci - @mankoff a raison ; c'est une question de longueur.

4voto

Jeff Swensen Points 581

Il y a deux solutions qui me viennent à l'esprit :

Le chemin le plus facile - Utilisation de la Info.plist dans chaque fichier .app Contents créez un index de la valeur pour les clés CFBundleExecutable. Puis ajoutez un alias court qui appelle un script (perl, Python, peu importe) avec le nom d'un exécutable et les arguments que vous souhaitez passer.

Votre index serait constitué de paires de noms d'exécutables et de chemins vers ces exécutables. Vous auriez à écrire un script programmé de façon récurrente pour le maintenir à jour.

Vous finiriez par pouvoir appeler :

f foo file.txt

où f est un alias vers un script qui vérifie votre index pour un exécutable nommé foo .

Dans l'ensemble, il n'y a pas beaucoup de travail pour obtenir la fonctionnalité souhaitée.

Le chemin le plus difficile - Étendez votre shell pour compléter la manipulation de son command_not_found erreur. Essentiellement, vous implémenteriez un style Ruby method_missing dans le shell que vous utilisez. Lorsque command_not_found a été déclenchée, votre méthode vérifierait les noms d'exécutables de vos applications installées.

2voto

eric Points 503

Applescript à la rescousse :

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

Remplacez le nom de l'application par celui de l'application que vous souhaitez démarrer et le tour est joué. Vous pouvez bien sûr en faire une fonction shell si nécessaire :

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

et l'utiliser de cette façon :

f iTunes

Je déteste applescript, mais il est utile parfois, et je crois que c'est le seul moyen de s'adresser à une application simplement par son nom sur la ligne de commande. Tout le reste nécessitera un chemin complet.

0 votes

Ne prend pas en charge la complétion par tabulation. Nécessite de se souvenir exactement des noms des applications. Je ne vois pas pourquoi AppleScript est nécessaire (surtout si on le déteste) si le script shell peut tout faire.

1 votes

Je n'avais jamais réalisé que open -a pouvait être utilisé sans nom de fichier comme argument. Et j'utilise open depuis NextStep parfois au début des années 90 ! S'il vous plaît soumettre cela comme une réponse afin que je puisse voter sur elle. Donc oui, la réponse correcte est d'utiliser 'open -a <nom de l'application>'.

LesApples.com

LesApples est une communauté de Apple où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres utilisateurs d'appareils Apple, poser vos propres questions ou résoudre celles des autres.

Powered by:

X