เริ่มต้นแอพ 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 เพื่อบอก open ว่าคุณต้องการแอพจาก Applications dir คุณควรเปลี่ยนนี้เพื่อคำตอบ :)
โรเบิร์ตเอ Ciaccio

@Reid: คุณสามารถแก้ไขคำถามเพื่อรวมบรรทัดคำสั่งตัวอย่างที่คุณต้องการพิมพ์ได้หรือไม่
Robert S Ciaccio

@mankoff ซึ่งหมายความว่าเขาต้องการนามแฝงสำหรับแน่ใจหรือส่วนขยายของความสำเร็จแท็บ
โรเบิร์ตเอ 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.

แก้ไขโดย Reid:

ฉันใช้งานข้างต้นเป็นสคริปต์ Python ที่สร้างสคริปต์ตัวตัดแทนชื่อแทน คุณจะต้องใส่~/bin/mankoffmagicในเส้นทางของคุณ ถ้าคุณต้องการให้ wrappers ได้รับการอัพเดตโดยอัตโนมัติให้รันเป็นประจำจาก cron หรือ 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" อยู่ในนั้นเพราะเพียงเครื่องหมายอะโพสโทรฟีใน "iWork '09" กำลังสับสน โปรดทราบว่าหากคุณเก็บแอปอื่น ๆ (~ / local / Applications) เพียงแค่เพิ่มแอพนั้นลงในlsคำสั่งและสิ่งนี้ก็จะใช้ได้เช่นกัน

ทำได้ดีนี่. ฉันชอบที่มันเป็นแบบไดนามิกดังนั้นคุณจึงไม่ต้องจบเรื่องการบำรุงรักษาใด ๆ เช่นการล้างนามแฝงเก่า
Robert S Ciaccio

ขอบคุณ @mankoff! มีกลิ่นที่ดี - เมื่อฉันทดสอบและใช้งานได้ฉันจะทำเครื่องหมายคำตอบที่ยอมรับแล้ว ชื่นชมมาก
Reid

ตกลงใช้งานได้ มันทำลายแอพที่มีเครื่องหมายอัญประกาศเดี่ยว (และตัวอักษรตลกอื่น ๆ ในชื่อ) ฉัน riffed ในโซลูชันของคุณและทำสิ่งที่คล้ายกันใน Python ซึ่งฉันจะโพสต์ในคำตอบอื่น - แม้ว่านั่นไม่ใช่มารยาทที่เหมาะสมฉันยินดีที่จะเพิ่มลงในคำตอบของคุณแทน (หรืออะไรก็ตาม)
Reid

8

คุณไม่ต้องการอะไรเลยคุณมีคำตอบอยู่แล้ว ลอง:

open /Applications/Foo.app bar.pdf

ในการแก้ไข

จากความคิดเห็นด้านล่างฉันคิดว่าคำตอบของฉันจะยังคงค่อนข้างคล้ายกัน ... ฉันจะทำให้ฟังก์ชั่นที่แทนที่เปิดเปิด pushd ไปที่การ/Applicationsโทร/usr/bin/open $appName.app $argsป๊อปอัพและกลับมา

ฉันดูดที่เชลล์สคริปต์ แต่สิ่งที่ด้านล่างซึ่งครอบคลุมกรณีพิเศษและช่วยให้คุณใช้ไวยากรณ์เดียวกับ Apple ที่เปิดไว้ ฉันชอบรักษาสภาพแวดล้อมให้สะอาดที่สุดเท่าที่จะทำได้

ฉันแน่ใจว่าไวยากรณ์มาจากนอกโลก:

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ได้ ดังนั้น mankoff อาจมีทางออกที่ง่ายที่สุดและควรเปลี่ยนความคิดเห็นของเขาเป็นคำตอบ;)


ฉันคิดว่า @Reid ต้องการวิธีที่สั้นกว่าโดยไม่มีการสร้างชื่อแทนด้วยตนเอง

แต่เขาไม่จำเป็นต้องสร้างนามแฝงสำหรับยูนิกซ์ที่ปฏิบัติการได้หากเขาใช้ 'เปิด' ในแพ็คเกจ. app ฉันได้รับความประทับใจว่าเขาสร้างนามแฝงเพราะเขาคิดว่าวิธีเดียวที่จะเริ่มแอพโดยตรงจากบรรทัดคำสั่งคือการไปยังไดเรกทอรี MacOS และดำเนินการไฟล์ที่เป็นไฟล์ 'ปฏิบัติการ' ภายในแอป ดังนั้นในกรณีนี้นามแฝงอย่างน้อยจะบันทึกการพิมพ์โครงสร้างไดเรกทอรีสามระดับพิเศษที่คุณต้องการเพื่อเริ่มแอป บางทีฉันอาจจะเข้าใจผิดคำถามของเขา
Robert S Ciaccio

@ calevara ขอบคุณ - @mankoff ถูกต้อง; มันเกี่ยวกับความยาว
เรด

3
นี่เป็นการนำฟังก์ชั่นการแก้ไขไปใช้ในทางที่ผิด หากคุณต้องการเสนอคำตอบที่สองให้ทำในภายหลัง อย่าแก้ไขคำตอบดั้งเดิมของคุณโดยทำการโหวตกลับไปที่ความคิดใหม่ของคุณ
Jeff Swensen

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

Applescript to the rescue:

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 <application name>'
eric
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.