Bắt đầu chính xác các ứng dụng Mac OS từ dòng lệnh


22

Tôi thực hiện một số lượng công việc khá lớn trong dòng lệnh và tôi thấy mình xác định rất nhiều bí danh của biểu mẫu:

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

Có cách nào để thêm phép thuật sao cho yêu cầu "foo" thực thi tự động sử dụng /Appluggest/Foo.app/Contents/MacOS/Foo thực thi không? Đây là trên OS X 10.6.

(Tôi biết rằng tôi có thể làm được open foo.pdf, nhưng Skim không phải là trình đọc PDF mặc định và tôi muốn một giải pháp chung - trong một số trường hợp, không phù hợp để đặt ứng dụng được đề cập làm trình xử lý mặc định cho tệp.)


22
Bạn có thể open -a Skim foo.pdf.

1
@mankoff: thật tuyệt, tôi quên bạn có thể sử dụng -a để nói với bạn rằng bạn muốn có một ứng dụng từ thư mục Ứng dụng. bạn nên thay đổi câu trả lời này :)
Robert S Ciaccio

@Reid: bạn có thể chỉnh sửa câu hỏi của mình để bao gồm một dòng lệnh ví dụ mà bạn đang muốn có thể nhập không?
Robert S Ciaccio

@mankoff có nghĩa là anh ta cần bí danh để chắc chắn hoặc gia hạn hoàn thành tab
Robert S Ciaccio

@Reid có vấn đề gì với giải pháp không?

Câu trả lời:


10

Cuối cùng tôi đã nhận được: Thêm cái này vào .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()

Bây giờ công việc sau đây:

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

Chỉnh sửa bởi Reid:

Tôi đã triển khai ở trên dưới dạng tập lệnh Python tạo tập lệnh bao bọc thay vì bí danh. Bạn sẽ cần phải đặt ~/bin/mankoffmagictrong con đường của bạn. Nếu bạn muốn các trình bao bọc được cập nhật tự động, hãy chạy nó thường xuyên từ cron hoặc 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" ở đó chỉ vì dấu nháy đơn trong "iWork '09" đang làm mọi thứ rối tung lên. Lưu ý rằng nếu bạn lưu trữ ứng dụng ở nơi khác (~ / local / Ứng dụng) chỉ cần thêm nó vào lslệnh và điều này cũng sẽ hoạt động ở đó.

tốt đẹp Tôi thích nó năng động vì vậy bạn không gặp phải bất kỳ vấn đề bảo trì nào như dọn dẹp các bí danh cũ.
Robert S Ciaccio

Cảm ơn @mankoff! Mùi tuyệt vời - một khi tôi đã thử nó và nó hoạt động tôi sẽ đánh dấu câu trả lời được chấp nhận. Nhiều đánh giá cao.
Reid

OK, cái này hoạt động. Nó không phá vỡ các ứng dụng với dấu nháy đơn (và có lẽ là các ký tự vui nhộn khác trong tên). Tôi đã riff về giải pháp của bạn và đã làm một cái gì đó tương tự trong Python, mà tôi sẽ đăng trong một câu trả lời khác - mặc dù nếu đó không phải là nghi thức đúng, tôi rất vui khi thêm nó vào câu trả lời của bạn (hoặc bất cứ điều gì).
Reid

8

Bạn không cần bất cứ điều gì lạ mắt, bạn đã có câu trả lời. Thử:

open /Applications/Foo.app bar.pdf

về chỉnh sửa

Trước những bình luận dưới đây, tôi nghĩ rằng câu trả lời của tôi vẫn tương đối giống nhau ... Tôi sẽ thực hiện một chức năng ghi đè mở, thực hiện một /Applicationscuộc gọi đến/usr/bin/open $appName.app $args , thực hiện một lệnh popd và trả về.

Tôi rất thích kịch bản shell nhưng một cái gì đó như bên dưới bao gồm các trường hợp đặc biệt và giữ cho bạn sử dụng khá nhiều cú pháp giống như apple được cung cấp để mở. Tôi thích giữ môi trường của mình sạch nhất có thể.

Tôi chắc chắn cú pháp là từ không gian bên ngoài:

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
}

trong lần chỉnh sửa thứ hai

Tìm kiếm bình luận của @ mankoff về câu hỏi ban đầu, hầu hết những thứ trong chức năng trên có thể sẽ lãng phí thời gian vì bạn chỉ có thể sử dụng open -a $appName. Vì vậy, mankoff có thể có giải pháp dễ nhất và nên thay đổi nhận xét của mình thành câu trả lời;)


Tôi nghĩ rằng @Reid muốn một cách ngắn hơn với cách tự tạo tất cả các bí danh.

Nhưng anh ta không phải tạo bí danh cho unix thực thi nếu anh ta sử dụng 'mở' trên gói .app. Tôi có ấn tượng rằng anh ta đang tạo bí danh vì anh ta nghĩ cách duy nhất để khởi động ứng dụng trực tiếp từ dòng lệnh là bằng cách đi vào thư mục MacOS và thực thi tệp có thể thực thi được trong ứng dụng. Vì vậy, trong trường hợp đó, một bí danh ít nhất sẽ tiết kiệm việc nhập ba cấp cấu trúc thư mục bổ sung mà bạn sẽ cần để khởi động ứng dụng. Có lẽ tôi đang hiểu nhầm câu hỏi của anh ấy.
Robert S Ciaccio

@calevara, cảm ơn - @mankoff là đúng; đó là về chiều dài.
Reid

3
Đây là một chút lạm dụng chức năng chỉnh sửa. Nếu sau này bạn muốn đề xuất một câu trả lời thứ hai, hãy làm điều đó. Không chỉnh sửa câu trả lời ban đầu của bạn, cõng số phiếu mà nó nhận được vào ý tưởng mới của bạn.
Jeff Swensen

1
Tôi không đồng ý ... câu trả lời vẫn khá giống nhau vì anh ta sẽ sử dụng cùng một cú pháp. Không chỉ vậy, nhưng nếu những người bỏ phiếu không thích câu trả lời mới, họ có thể thay đổi phiếu bầu của mình vì câu trả lời đã được chỉnh sửa. Đó chính xác là lý do tại sao bạn có thể thay đổi phiếu bầu của mình sau khi chỉnh sửa. Đó cũng là lý do tại sao tôi đặt "chỉnh sửa" in đậm.
Robert S Ciaccio

4

Có hai giải pháp mà tôi có thể nghĩ ra:

Cách dễ dàng hơn - Sử dụng Info.plisttệp trong mỗi .appContents thư mục , tạo chỉ mục giá trị cho các khóa CFBundleExecutable. Sau đó, thêm một bí danh ngắn gọi một tập lệnh (perl, python, bất cứ thứ gì) với tên của một tệp thực thi và các đối số bạn muốn vượt qua.

Chỉ mục của bạn sẽ là các cặp tên và đường dẫn thực thi đến các tệp thực thi đó. Bạn sẽ phải viết một kịch bản theo lịch trình định kỳ để cập nhật thông tin này.

Cuối cùng, bạn sẽ có thể gọi:

f foo file.txt

trong đó f là bí danh của tập lệnh kiểm tra chỉ mục của bạn để tìm tên thực thi foo .

Nói chung, không có nhiều công việc để có được chức năng bạn muốn.

Cách khó hơn - Mở rộng vỏ của bạn để bổ sung cho việc xử lý command_not_foundlỗi của nó . Về cơ bản, bạn sẽ triển khai method_missingchức năng kiểu Ruby trong bất kỳ lớp vỏ nào bạn đang sử dụng. Khi command_not_foundbị ném, phương thức của bạn sẽ kiểm tra tên thực thi của Ứng dụng đã cài đặt.


2

Applescript để giải cứu:

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

Thay thế tên của ứng dụng bằng ứng dụng bạn muốn bắt đầu và bạn đã hoàn thành. Tất nhiên bạn có thể làm cho nó một hàm shell nếu cần:

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

và sử dụng nó theo cách đó:

f iTunes

Tôi ghét applescript, nhưng đôi khi nó rất hữu ích và tôi tin rằng cách duy nhất để giải quyết một ứng dụng chỉ bằng tên trên dòng lệnh. Mọi thứ khác sẽ yêu cầu một con đường đầy đủ.


Không hỗ trợ hoàn thành tab. Yêu cầu nhớ chính xác tên ứng dụng. Đừng xem tại sao AppleScript được yêu cầu (đặc biệt là nếu bạn ghét nó) nếu shell script có thể làm tất cả.

1
Tôi không bao giờ nhận ra rằng open -a có thể được sử dụng mà không có tên tệp làm đối số. Và tôi đã sử dụng open kể từ NextStep đôi khi vào đầu những năm 90! Vui lòng gửi nó như một câu trả lời để tôi có thể bỏ phiếu cho nó. Vì vậy, có, câu trả lời đúng là sử dụng 'open -a <tên ứng dụng>'
eric
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.