bash 在 Mac OS (OS X) 中登录时启动 shell 脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22842016/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 00:46:33  来源:igfitidea点击:

Launch shell script on login in Mac OS (OS X)

macosbashshell

提问by user3472065

I have this shell script Test.sh:

我有这个 shell 脚本Test.sh

#! /bin/bash

FILE_TO_CHECK="/Users/test/start.txt"
EXIT=0

while [ $EXIT -eq 0 ]; do
    if [ -f "$FILE_TO_CHECK" ]
        then
        /usr/bin/java -jar myapp.jar
        EXIT=1
    else
        sleep 30
    fi
done

I need to start this script automatically after login.
So I put it inside a folder Testin /System/Library/StartupItems/

我需要在登录后自动启动这个脚本。
所以我把它放在一个文件夹Test/System/Library/StartupItems/

When I reboot the Mac, nothing happens after I log in. Any clue?

当我重新启动 Mac 时,登录后没有任何反应。有任何线索吗?

I also tried Automator, but with the same result: the java program is not running.

我也尝试过Automator,但结果相同:java 程序没有运行。

采纳答案by Ivan Kovacevic

You can't just place plain scripts in that folder. You need a "specialized bundle"how Apple calls it, basically a folder with your executable, and a .plistconfiguration. And you should put it in /Library/StartupItemssince /System/Library/StartupItems/is reserved for the operating system. Read all about it here:

您不能只将普通脚本放在该文件夹中。您需要一个Apple 如何称呼它的“专用包”,基本上是一个包含可执行文件的文件夹和一个.plist配置。您应该将它放在/Library/StartupItems 中,因为/System/Library/StartupItems/是为操作系统保留的。在这里阅读所有相关信息:

https://developer.apple.com/library/mac/documentation/macosx/conceptual/bpsystemstartup/chapters/StartupItems.html

https://developer.apple.com/library/mac/documentation/macosx/conceptual/bpsystemstartup/chapters/StartupItems.html

Also note that the whole stuff is marked as deprecated technology. And that Apple is suggesting the use of launchd. There is an example how to set it up here:

另请注意,整个内容都被标记为已弃用的技术。并且 Apple 建议使用launchd。这里有一个如何设置的示例:

https://superuser.com/questions/229773/run-command-on-startup-login-mac-os-x

https://superuser.com/questions/229773/run-command-on-startup-login-mac-os-x

回答by mklement0

Ivan Kovacevic's pointers, especially the superuser.com link, are helpful; since at least OS X 10.9.2, your options for creating run-at-login scriptsare:

Ivan Kovacevic 的提示,尤其是 superuser.com 链接,很有帮助;至少从 OS X 10.9.2 开始,创建登录时运行脚本的选项是:

Note: The methods are annotated with respect to whether they are:

注意:这些方法是关于它们是否为:

  • specific to a given user ("[user-SPECIFIC]"); i.e., the installation must be performed for eachuser, if desired; scripts are typically stored in a user-specific location, and root (administrative) privileges are NOT required for installation.
  • effective for ALL users ("[ALL users]"); i.e., the installation takes effect for ALL users; scripts are typically stored in a shared locationand root (administrative) privilegesARE required for installation.
  • 特定于给定用户(“ [ user-SPECIFIC]”);即,如果需要,必须为每个用户执行安装;脚本通常存储在用户特定的位置,安装不需要 root(管理)权限。
  • 对所有用户有效(“ [所有用户]”);即安装对所有用户生效;脚本通常存储在共享位置,安装需要root(管理)权限

The scripts themselves will run invisibly, but - with the exception of the com.apple.loginwindowlogin-hook method - you can open applications visibly from them; things to note:

脚本本身将不可见地运行,但是 - 除了com.apple.loginwindowlogin-hook 方法 - 您可以从它们可见地打开应用程序;注意事项:

  • There is no guarantee that any such application will be frontmost, so it may be obscured by other windows opened during login.

  • If you want to run another shell scriptvisibly, simply use open /path/to/your-script, which will open it in Terminal.app; however, the Terminal window will automatically close when your script terminates.

  • 不能保证任何此类应用程序将位于最前面,因此它可能会被登录期间打开的其他窗口遮挡。

  • 如果您想明显地运行另一个shell 脚本,只需使用open /path/to/your-script,它将在Terminal.app; 但是,当您的脚本终止时,终端窗口将自动关闭。



Automator [user-SPECIFIC]:

Automator [用户特定]

  • File > New, type Application
  • Add a Run Shell Scriptaction, which adds an embedded bashscript, and either paste your script code there or add a command that invokes an existing script from there.
  • Save the *.appbundle and add it to the Login Itemslist in System Preferences > User & Groups > Login Items.

    Note:

    • The embedded script runs with the default "C"locale.
    • $PATHis fixed to /usr/bin:/bin:/usr/sbin:/sbin, which notably does NOT include /usr/local/bin
    • The working dir. is the current user's home directory.
  • File > New, 类型 Application
  • 添加一个Run Shell Script操作,它添加一个嵌入式bash脚本,然后将您的脚本代码粘贴到那里,或者添加一个从那里调用现有脚本的命令。
  • 保存*.app捆绑,并将其添加到Login Items列表中System Preferences > User & Groups > Login Items

    笔记:

    • 嵌入式脚本使用默认"C"语言环境运行。
    • $PATH固定为/usr/bin:/bin:/usr/sbin:/sbin,其中不包括/usr/local/bin
    • 工作目录。是当前用户的主目录


com.apple.loginwindowlogin hook [ALL users- DEPRECATED, but still works]:

com.apple.loginwindow登录钩子 [所有用户- 已弃用,但仍然有效]

If you have admin privileges, this is the easiest method, but it is DEPRECATED, for a variety of reasons (security, limited to a single, shared script, synchronous execution); Apple especially cautions against use of this mechanism as part of a software product.

如果您有管理员权限,这是最简单的方法,但由于各种原因(安全、仅限于单个、共享脚本、同步执行),它已被弃用;Apple 特别警告不要将此机制用作软件产品的一部分。

  • Place your script, e.g., Test.sh, in a shared location - e.g., /Users/Shared- and make sure it is executable (chmod +x /Users/Shared/Test.sh).
  • From Terminal.app, run the following:

    sudo defaults write com.apple.loginwindow LoginHook /Users/Shared/Test.sh

  • Note:

    • The script will run as the rootuser, so exercise due caution.
      Among the methods listed here, this is the only way to run a script as root.

    • There's only onesystem-wide login hook.

      • Note that there's also a log-OUT hook, LogoutHook, which provides run-at-logout functionality - unlike the other approaches.
    • The login-hook script runs synchronously beforeother login actions, and should therefore be kept short.

      • Notably, it runs beforethe desktop is displayed; you cannot launch applicationsfrom the script, but you can create simple interactions via osascriptand AppleScript snippets (e.g., osascript -e 'display dialog "Proceed?"'); however, any interactions blockthe login process.
    • The script runs in the context of the rootuser and he username of the user logging on is passed as the 1st argument to the script.

    • The script runs with the default "C"locale.
    • $PATHis fixed to /usr/bin:/bin:/usr/sbin:/sbin, which notably does NOT include /usr/local/bin
    • The working dir. is /.
  • 将您的脚本(例如 )Test.sh放在共享位置 - 例如/Users/Shared- 并确保它是可执行的 ( chmod +x /Users/Shared/Test.sh)。
  • Terminal.app,运行以下命令:

    sudo defaults write com.apple.loginwindow LoginHook /Users/Shared/Test.sh

  • 笔记:

    • 脚本将以root用户身份运行,因此请谨慎操作
      在此处列出的方法中,这是以root身份运行脚本的唯一方法。

    • 只有一个系统范围的登录挂钩。

      • 请注意,还有一个注销挂钩,LogoutHook它提供注销时运行功能 - 与其他方法不同。
    • login-hook 脚本其他登录操作之前同步运行,因此应该保持简短

      • 值得注意的是,它显示桌面之前运行;您无法从脚本启动应用程序,但您可以通过osascriptAppleScript 片段(例如,osascript -e 'display dialog "Proceed?"')创建简单的交互;但是,任何交互都会阻止登录过程。
    • 该脚本在root用户的上下文中运行,登录用户的用户名作为第一个参数传递给脚本。

    • 该脚本使用默认"C"语言环境运行。
    • $PATH固定为/usr/bin:/bin:/usr/sbin:/sbin,其中不包括/usr/local/bin
    • 工作目录。是/


launchd agents:

启动代理

launchd-agent-executed scripts can be installed for a SPECIFIC user OR for ALL users - the latter requires administrative privileges.

launchd可以为特定用户或所有用户安装代理执行的脚本 - 后者需要管理权限。

While using launchdis Apple's preferred method, it's also the most cumbersome, as it requires creating a separate *.plistconfiguration file.
On the upside, you can install multiple scripts independently.

虽然使用launchd是 Apple 的首选方法,但它也是最麻烦的,因为它需要创建一个单独的*.plist配置文件。
从好的方面来说,您可以独立安装多个脚本。

  • Note:
    • No specific timing or sequencing of launchdscripts is guaranteed; loosely speaking, they "run at the same time at login"; there is even no guaranteed timing between the user-specific and the all-user tasks.
    • The script runs with the default "C"locale.
    • $PATHis fixed to /usr/bin:/bin:/usr/sbin:/sbin, which notably does NOT include /usr/local/bin
    • The working dir. is /by default, but you can configure it via the .plistfile - see below.
    • The script-file path must be specified as a full, literal path(e.g., /Users/jdoe/script.sh; notably , ~-prefixed paths do notwork.
    • For a description of all keys that can be used in *.plistconfiguration files, see man launchd.plist.
    • Both user-specific and all-users tasks run as the currentuser (the user logging on).
  • 笔记:
    • launchd保证脚本的特定时间或顺序;松散地说,它们“在登录时同时运行”;在特定于用户的任务和所有用户的任务之间甚至没有保证的时间安排。
    • 该脚本使用默认"C"语言环境运行。
    • $PATH固定为/usr/bin:/bin:/usr/sbin:/sbin,其中不包括/usr/local/bin
    • 工作目录。是/默认,但你可以通过它配置.plist文件-见下文。
    • 该脚本文件路径必须被指定为一个完整,文字的路径(例如/Users/jdoe/script.sh,值得注意的是,~-prefixed路径就不会工作。
    • 有关可在*.plist配置文件中使用的所有键的说明,请参阅man launchd.plist
    • 用户特定任务和所有用户任务都以当前用户(登录用户)身份运行。


launchd [user-SPECIFIC]:

启动 [用户特定]

  • Note: Lingon 3($5 as of early 2014) is a GUI application that facilitates the process below, but only for user-specificscripts.
  • Place your script, e.g., Test.sh, in your home folder, e.g., /Users/jdoe
  • Create a file with extension .plistin ~/Library/LaunchAgents, e.g., ~/Library/LaunchAgents/LoginScripts.Test.plist, by running the following in Terminal.app:

    touch ~/Library/LaunchAgents/LoginScripts.Test.plist
    
  • Open the file and save it with the following content:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
          <!-- YOUR SELF-CHOSEN *UNIQUE* LABEL (TASK ID) HERE -->
        <string>LoginScripts.Test.sh</string>
        <key>ProgramArguments</key>
        <array>
              <!-- YOUR *FULL, LITERAL* SCRIPT PATH HERE -->
            <string>/Users/jdoe/Test.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
    </dict>
    </plist>
    
  • The <!-- ... -->comments indicate the places to customize; you're free to choose a label, but it should be unique - ditto for the .plistfilename; for simplicity, keep the label and the filename root the same.

  • From Terminal.app, run the following:

    launchctl load ~/Library/LaunchAgents/LoginScripts.Test.plist
    
  • Note that, as a side effect, the script will execute right away. From that point on, the script will execute whenever the CURRENT user logs on.

  • It is not strictly necessary to run launchctl load-- since, by virtue of the file's location, it will be picked up automatically on next login -- but it's helpful for verifying that the file loads correctly.
  • 注意:(Lingon 3截至 2014 年初为 5 美元)是一个 GUI 应用程序,可促进以下过程,但仅适用于用户特定的脚本。
  • 将您的脚本,例如,Test.sh放在您的主文件夹中,例如,/Users/jdoe
  • 创建一个扩展名为.plistin的文件~/Library/LaunchAgents,例如~/Library/LaunchAgents/LoginScripts.Test.plist,通过在 中运行以下命令Terminal.app

    touch ~/Library/LaunchAgents/LoginScripts.Test.plist
    
  • 打开文件并将其保存为以下内容:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
          <!-- YOUR SELF-CHOSEN *UNIQUE* LABEL (TASK ID) HERE -->
        <string>LoginScripts.Test.sh</string>
        <key>ProgramArguments</key>
        <array>
              <!-- YOUR *FULL, LITERAL* SCRIPT PATH HERE -->
            <string>/Users/jdoe/Test.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
    </dict>
    </plist>
    
  • <!-- ... -->意见指出地方来定制; 您可以自由选择标签,但它应该是唯一的——.plist文件名也是如此;为简单起见,保持标签和文件名根相同。

  • Terminal.app,运行以下命令:

    launchctl load ~/Library/LaunchAgents/LoginScripts.Test.plist
    
  • 请注意,作为副作用,脚本将立即执行。从那时起,只要 CURRENT 用户登录,脚本就会执行。

  • 运行并不是绝对必要的launchctl load——因为根据文件的位置,它将在下次登录时自动选取——但它有助于验证文件是否正确加载。


launchd [ALL users]

启动 [所有用户]

  • Place your script, e.g., Test.sh, in a SHARED location, e.g., /Users/Shared
  • Create a file with extension .plistin /Library/LaunchAgents(requires admin privileges), e.g., /Library/LaunchAgents/LoginScripts.Test.plist, by running the following in Terminal.app:

    sudo touch /Library/LaunchAgents/LoginScripts.Test.plist
    
  • Open the file and save it with the following content (make sure your text editor prompts for admin privileges on demand; alternatively, use sudo nano /Library/LaunchAgents/LoginScripts.Test.plist):

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
          <!-- YOUR SELF-CHOSEN *UNIQUE* LABEL (TASK ID) HERE -->
        <string>LoginScripts.Test.sh</string>
        <key>ProgramArguments</key>
        <array>
              <!-- YOUR *FULL, LITERAL* SCRIPT PATH HERE -->
            <string>/Users/Shared/Test.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
    </dict>
    </plist>
    
  • The <!-- ... -->comments indicate the places to customize; you're free to choose a label, but it should be unique - ditto for the .plistfilename; for simplicity, keep the label and the filename root the same.

  • From Terminal.app, run the following:

    sudo chown root /Library/LaunchAgents/LoginScripts.Test.plist
    sudo launchctl load /Library/LaunchAgents/LoginScripts.Test.plist
    
  • Note that, as a side effect, the script will execute right away. From that point on, the script will execute whenever ANY user logs on.

  • It is not strictly necessary to run launchctl load-- since, by virtue of the file's location, it will be picked up automatically on next login -- but it's helpful for verifying that the file loads correctly.
  • 将您的脚本,例如,Test.sh放在共享位置,例如,/Users/Shared
  • 创建一个扩展名为.plistin /Library/LaunchAgents(需要管理员权限)的文件,例如/Library/LaunchAgents/LoginScripts.Test.plist,通过在 中运行以下命令Terminal.app

    sudo touch /Library/LaunchAgents/LoginScripts.Test.plist
    
  • 打开文件并将其保存为以下内容(确保您的文本编辑器根据需要提示输入管理员权限;或者,使用sudo nano /Library/LaunchAgents/LoginScripts.Test.plist):

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
          <!-- YOUR SELF-CHOSEN *UNIQUE* LABEL (TASK ID) HERE -->
        <string>LoginScripts.Test.sh</string>
        <key>ProgramArguments</key>
        <array>
              <!-- YOUR *FULL, LITERAL* SCRIPT PATH HERE -->
            <string>/Users/Shared/Test.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
    </dict>
    </plist>
    
  • <!-- ... -->意见指出地方来定制; 您可以自由选择标签,但它应该是唯一的——.plist文件名也是如此;为简单起见,保持标签和文件名根相同。

  • Terminal.app,运行以下命令:

    sudo chown root /Library/LaunchAgents/LoginScripts.Test.plist
    sudo launchctl load /Library/LaunchAgents/LoginScripts.Test.plist
    
  • 请注意,作为副作用,脚本将立即执行。从那时起,该脚本将在任何用户登录时执行。

  • 运行并不是绝对必要的launchctl load——因为根据文件的位置,它将在下次登录时自动选取——但它有助于验证文件是否正确加载。

回答by Quanlong

launchd-oneshotis used to install script as a launchd job to run on login, with

launchd-oneshot用于将脚本安装为启动作业以在登录时运行,使用

brew install cybertk/formulae/launchd-oneshot
sudo launchd-oneshot Test.sh --on-login