Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
750 views
in Technique[技术] by (71.8m points)

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

I have this shell script 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 Test in /System/Library/StartupItems/

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

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 scripts are:

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 each user, 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 location and root (administrative) privileges ARE required for installation.

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

  • 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 script visibly, 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.


Automator [user-SPECIFIC]:

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

    Note:

    • The embedded script runs with the default "C" locale.
    • $PATH is 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.

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

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.

  • 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 root user, so exercise due caution.
      Among the methods listed here, this is the only way to run a script as root.

    • There's only one system-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 before other login actions, and should therefore be kept short.

      • Notably, it runs before the desktop is displayed; you cannot launch applications from the script, but you can create simple interactions via osascript and AppleScript snippets (e.g., osascript -e 'display dialog "Proceed?"'); however, any interactions block the login process.
    • The script runs in the context of the root user 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.
    • $PATH is fixed to /usr/bin:/bin:/usr/sbin:/sbin, which notably does NOT include /usr/local/bin
    • The working dir. is /.

launchd agents:

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

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

  • Note:
    • No specific timing or sequencing of launchd scripts 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.
    • $PATH is 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 .plist file - see below.
    • The script-file path must be specified as a full, literal path (e.g., /Users/jdoe/script.sh; notably , ~-prefixed paths do not work.
    • For a description of all keys that can be used in *.plist configuration files, see man launchd.plist.
    • Both user-specific and all-users tasks run as the current user (the user logging on).

launchd [user-SPECIFIC]:

  • Note: Lingon 3 ($5 as of early 2014) is a GUI application that facilitates the process below, but only for user-specific scripts.
  • Place your script, e.g., Test.sh, in your home folder, e.g., /Users/jdoe
  • Create a file with extension .plist in ~/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 .plist filename; 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.

launchd [ALL users]

  • Place your script, e.g., Test.sh, in a SHARED location, e.g., /Users/Shared
  • Create a file with extension .plist in /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 .plist filename; 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.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...