22 votos

Comenzar de forma concisa las aplicaciones de Mac OS desde la línea de comandos

Hago una cantidad considerable de trabajo en la línea de comandos, y me encuentro definiendo muchas alias de la forma:

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

¿Hay alguna manera de agregar un comando mágico para que al solicitar el ejecutable "foo", automáticamente se use el ejecutable /Applications/Foo.app/Contents/MacOS/Foo? Esto es en OS X 10.6.

(Sé que podría hacer open foo.pdf, pero Skim no es el lector de PDF predeterminado, y me gustaría una solución general - en algunos casos, no es apropiado establecer la aplicación en cuestión como el manejador predeterminado para el archivo.)

10voto

Finalmente lo conseguí: Agrega esto a tu .bash_profile

function foomagick() {
    rm -f ~/.foomagick.tmp
    ls /Applications/ | grep "\.app" | grep -v iWork | while read APP; do
        # limpiarlo
        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()

Ahora lo siguiente funciona:

Skim # abrir Skim.app
Skim foo.pdf
FireFox http://google.com
FireFox google.com # ERROR. Busca archivo local.

Editado por Reid:

Implementé lo anterior como un script de Python que crea scripts envoltorios en lugar de alias. Necesitarás poner ~/bin/mankoffmagic en tu ruta. Si quieres que los envoltorios se actualicen automáticamente, ejecútalo regularmente desde cron u otro método.

#!/usr/bin/python
#
# Este script actualiza automáticamente un conjunto de scripts de shell envolventes en
# ~/bin/mankoffmagic que llama a aplicaciones de Mac instaladas en /Applications.
#
# Inspirado en el alias de shell de mankoff publicado en apple.stackexchange.com; vea:
# http://apple.stackexchange.com/questions/4240/concisely-starting-mac-os-apps-from-the-command-line/4257#4257
#
# Notas/Errores:
#
# 1. No sigue enlaces simbólicos (¿alias?)
#
# 2. Supone que los nombres de aplicaciones no contienen comillas dobles.
#
# 3. No es muy inteligente para encontrar el binario real (hace una suposición). Esto es
# incorrecto a veces, por ejemplo, Firefox. Probablemente una comprensión más profunda de la estructura del paquete de la aplicación
# solucionaría esto.

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():
   # Eliminamos agresivamente todo lo que ya está en BINDIR, para evitar el problema
   # de analizar lo que debería quedarse
   for f in glob.glob("%s/*" % BINDIR):
      os.unlink(f)

   # Recorre /Applications y crea un script de shell envolvente para cada directorio .app
   for (root, dirs, files) in os.walk("/Applications"):
      dirs_real = copy.copy(dirs)  # para poder manipular dirs mientras se recorre
      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 es necesario reaccionar en la app
            create_script(root, d, m.group(1))

def create_script(path, appdir, appname):
   # eliminar no alfanuméricos y pasarlo a minúsculas
   wrapper = STRIP_RE.sub('', appname).lower()
   wrapper = os.path.join(BINDIR, wrapper)
   fp = open(wrapper, "w")
   # Ajustar los comentarios en el script dependiendo de si quieres
   # invocar el binario o usar "open" -- el primero te permite usar cualquier
   # argumento de línea de comandos, mientras que el segundo es más al estilo de Mac (la app se pone al frente, 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()

8voto

Shawn Puntos 8120

No necesitas nada elegante, ya tienes la respuesta. Prueba:

open /Applications/Foo.app bar.pdf

en edición

A la luz de los comentarios a continuación, creo que mi respuesta seguiría siendo relativamente similar... Haría una función que anula open, realiza un pushd a /Applications, llama a /usr/bin/open $appName.app $args, hace un popd y devuelve.

Soy malo en scripting de shell pero algo como lo siguiente que cubre casos especiales y te mantiene utilizando prácticamente la misma sintaxis que Apple proporcionó para open. Me gusta mantener mi entorno lo más limpio posible.

Estoy seguro de que la sintaxis es de otro mundo:

function open($appName, $args)
{
    #si estamos llamando a open sin una ruta como /Applications/TextEdit.app Y
    #    $appName termina en '.app'
    if (!tienePadre($appName) && esApp($appName))
    {
        pushd /Applications
        /usr/bin/open ${appName}.app $args &
        popd
        return
    }
    #de lo contrario, usa open como de costumbre
    /usr/bin/open $appName $args
    return
}

en segunda edición

mirando el comentario de @mankoff en la pregunta original, la mayoría de las cosas en la función anterior probablemente serían una pérdida de tiempo ya que podrías simplemente usar open -a $appName. Así que mankoff probablemente tiene la solución más fácil y debería cambiar su comentario a una respuesta ;)

4voto

David Locke Puntos 128

Hay dos soluciones que se me ocurren:

La manera más fácil - Utilizando el archivo Info.plist en cada directorio de .app Contents, crear un índice del valor para las claves CFBundleExecutable. Luego agregar un alias corto que llame a un script (perl, python, lo que sea) con el nombre de un ejecutable y los argumentos que le gustaría pasar.

Su índice serían pares de nombres de ejecutables y rutas a esos ejecutables. Tendría que escribir un script programado recurrente para mantener esto actualizado.

Terminarías pudiendo llamar a:

f foo file.txt

donde f es un alias a un script que revisa su índice en busca de un ejecutable llamado foo.

En general, no es mucho trabajo obtener la funcionalidad que le gustaría.

La manera más difícil - Extienda su shell para complementar el manejo de su error command_not_found. Básicamente implementaría una funcionalidad de estilo Ruby method_missing dentro de cualquier shell que esté utilizando. Cuando se lance el error command_not_found, su método verificaría los nombres de los ejecutables de las aplicaciones instaladas.

2voto

David Rabinowitz Puntos 130

Applescript al rescate:

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

Sustituye el nombre de la aplicación con la aplicación que deseas iniciar y listo. Por supuesto, puedes convertirlo en una función de shell si es necesario:

function f() {
    osascript <

`

y úsalo de esta manera:

f iTunes

Odio Applescript, pero a veces es útil, y creo que es la única forma de dirigirse a una aplicación simplemente por su nombre en la línea de comandos. Todo lo demás requerirá una ruta completa.

`

AppleAyuda.com

AppleAyuda es una comunidad de usuarios de los productos de Apple en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X