Запуск програми Mac OS з командного рядка


22

Я виконую досить велику роботу в командному рядку, і я вважаю, що визначаю багато псевдонімів форми:

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

Чи є спосіб додати магію, щоб запит на виконуваний "foo" автоматично використовував виконуваний файл /Applications/Foo.app/Contents/MacOS/Foo? Це в OS X 10.6.

(Я знаю, що міг би зробити open foo.pdf, але Skim - це не зчитувач файлів PDF за замовчуванням, і я хотів би загальне рішення - у деяких випадках не доцільно встановлювати відповідну програму як обробник за замовчуванням для файлу.)


22
Можна open -a Skim foo.pdf.

1
@mankoff: приємно, я забув, ти можеш використовувати -a, щоб відкрити, що ти хочеш додаток із редактора програм. Ви повинні змінити це на відповідь :)
Robert S Ciaccio

@Reid: чи можете ви відредагувати своє запитання, щоб включити приклад командного рядка, який ви хочете ввести?
Robert S Ciaccio

@mankoff, що означає, що йому потрібні псевдоніми для впевненого або продовження вкладки
Robert S Ciaccio

@Повторити проблеми з рішенням?

Відповіді:


10

Нарешті я зрозумів: додайте це до свого .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()

Тепер наступна робота:

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

Редагувати:

Я реалізував вище, як сценарій Python, який робить сценарії обгортки замість псевдонімів. Вам потрібно буде поставити ~/bin/mankoffmagicна свій шлях. Якщо ви хочете, щоб обгортки оновлювалися автоматично, запускайте їх регулярно з крона або чогось іншого.

#!/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" є лише тому, що апостроф у "iWork '09" псує речі. Зауважте, що якщо ви зберігаєте додатки в іншому місці (~ / local / Applications), просто додайте їх до lsкоманди, і це також буде працювати.

хороший. мені подобається, що це динамічно, тому у вас не виникає жодних проблем із технічним обслуговуванням, таких як прибирання старих псевдонімів.
Robert S Ciaccio

Дякую @mankoff! Пахне чудово - як тільки я це перевірю, і він працює, я позначу відповідь прийнятою. Цінується.
Рейд

Гаразд, це працює. Він не працює на додатки з апострофом (і, мабуть, іншими смішними символами в імені). Я розробив ваше рішення і зробив щось подібне в Python, про що я напишу в іншій відповіді - хоча якщо це не правильний етикет, я радий додати його до вашої відповіді замість цього (або будь-якого іншого).
Рейд

8

Вам не потрібно нічого фантазії, у вас вже є відповідь. Спробуйте:

open /Applications/Foo.app bar.pdf

на редагування

Зважаючи на коментарі нижче, я думаю, що моя відповідь все ще буде відносно схожою ... Я би зробив функцію, яка перекриває перегляд, робить pushd /Applications, дзвонить /usr/bin/open $appName.app $args, робить popd і повертається.

Я засмоктую сценарій оболонки, але щось на кшталт нижче, яке охоплює особливі випадки, і дозволяє вам використовувати майже той самий синтаксис, що і яблуко для відкритих. Мені подобається підтримувати своє оточення максимально чистим.

Я впевнений, що синтаксис з космосу:

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
}

при другій редакції

дивлячись на коментар @ mankoff щодо оригінального запитання, більшість речей у наведеній вище функції, ймовірно, будуть марною тратою часу, оскільки ви могли просто використовувати open -a $appName. Тож манкофф, мабуть, має найпростіше рішення і повинен змінити свій коментар на відповідь;)


Я думаю, що @Reid хоче коротший спосіб без ручного створення всіх псевдонімів.

Але йому не потрібно створювати псевдонім виконуваного файлу unix, якщо він використовує 'open' у пакеті .app. У мене склалося враження, що він створює псевдоніми, тому що думав, що єдиний спосіб запустити додаток безпосередньо з командного рядка - пройти весь шлях до каталогу MacOS і виконати файл, який є "справжнім" виконуваним в додатку. Тож у такому випадку псевдонім принаймні заощадить, ввівши додаткові три рівні структури каталогу, які вам знадобляться для запуску програми. Можливо, я нерозумію його питання.
Robert S Ciaccio

@calevara, дякую - @mankoff правий; йдеться про довжину.
Рейд

3
Це трохи неправильне використання функцій редагування. Якщо згодом ви хочете запропонувати другу відповідь, зробіть саме це. Не редагуйте оригінальну відповідь, підробляючи голоси, отримані вами за вашу нову ідею.
Джефф Свенсен

1
Я не згоден ... відповідь все ще досить схожа, тому що він використовує той самий синтаксис. Мало того, але якщо виборцям не подобається нова відповідь, вони можуть змінити свій голос, оскільки відповідь було відредаговано. Саме тому ви можете змінити свій голос після змін. Це також, чому я ставлю "редагувати" жирним шрифтом.
Robert S Ciaccio

4

Я можу придумати два рішення:

Найпростіший спосіб - використовуючи Info.plistфайл у кожному Contentsкаталозі .app , створіть індекс значення для ключів CFBundleExecutable. Потім додайте короткий псевдонім, який викликає скрипт (perl, python, що завгодно) з ім'ям виконавчого файлу та аргументами, які ви хочете передати.

Ваш індекс буде парами імен виконуваних файлів та шляхів до цих виконуваних файлів. Вам потрібно буде написати повторюваний запланований сценарій, щоб оновити це оновлення.

Ви зможете зателефонувати:

f foo file.txt

де f - псевдонім скрипту, який перевіряє ваш індекс на виконаний ім'я foo.

Загалом, не так багато роботи, щоб отримати потрібний вам функціонал.

Найскладніший спосіб - розгорніть оболонку, щоб доповнити обробку її command_not_foundпомилки. По суті, ви б реалізували method_missingфункціональність у стилі Ruby в будь-якій оболонці, яку ви використовуєте. Коли вас command_not_foundкинули, ваш метод перевірить назви виконуваних файлів встановлених додатків.


2

Яблукопис на допомогу:

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

Замініть назву програми на програму, яку ви хочете запустити, і ви закінчили. Ви, звичайно, можете зробити це функцією оболонки, якщо потрібно:

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

і використовувати його таким чином:

f iTunes

Я ненавиджу яблучний сценарій, але він іноді корисний, і я вважаю, що єдиний спосіб звернутися до програми просто по імені в командному рядку. Все інше вимагатиме повного шляху.


Не підтримує заповнення вкладки. Потрібно точно запам’ятати назви додатків. Не розумійте, чому потрібен AppleScript (особливо якщо ви його ненавидите), якщо сценарій оболонки може це зробити.

1
Я ніколи не розумів, що open -a може бути використаний без імені файлу як аргументу. І я використовую відкритий з NextStep іноді на початку 90-х! Будь ласка, подайте це як відповідь, щоб я міг проголосувати за нього. Отже, так, правильною відповіддю є використання 'open -a <назва програми>'
eric
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.