簡體   English   中英

在 Mac 上使用 launchd 自動運行 shell 腳本

[英]running a shell script automatically with launchd on Mac

我正在嘗試讓腳本每天同時運行以重新啟動 Mac。 我無法使用節能首選項面板中的內置計划功能,因為我運行的應用程序阻止了正常重啟。 如果我通過終端中的shutdown命令啟動重新啟動,無論哪些應用程序可能阻止它,它都會強制重新啟動。

我真的是 shell 腳本和啟動的新手,所以我真的是新手級別,所以請記住這一點。 這是我在這里的第一篇文章,但多年來我定期訪問並通常找到我正在尋找的答案。

在嘗試了各種事情之后,我有點遇到了障礙。 我現在的位置是我的 /Library/LaunchDaemons 文件夾中有一個 .plist 文件,該文件指向應該在特定時間運行的腳本。 我最初嘗試使用在線教程中的代碼在 bbedit 中編寫 .plist 文件。 它總是無法加載到launchctl(手動或通過重新啟動)。 然后我嘗試在 Xcode 中使用 plist 編輯器,這似乎效果更好。

完成后,plist 將加載到 launchctl。 它似乎也嘗試在指定時間運行腳本。 我查看了控制台,似乎 Mac 確實嘗試運行腳本,但失敗並出現以下錯誤:

com.apple.xpc.launchd[1] (com.apple.restart.sh[940]):服務退出異常代碼:1

我試過直接從終端運行腳本,例如sh scriptname和 Mac 重新啟動。

這是腳本:

#!/bin/bash
shutdown -r now

我將腳本保存在 /Library/Scripts 文件夾中。

這是.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>
    <string>com.apple.restart.sh</string>
    <key>Program</key>
    <string>/Library/Scripts/com.apple.restart.sh</string>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>9</integer>
        <key>Minute</key>
        <integer>50</integer>
    </dict>
</dict>
</plist>

我現在真的不知道出了什么問題,因為 .plist 似乎成功加載到 launchctl 並且腳本嘗試在指定時間運行但失敗。 如果腳本是手動運行的,它可以工作。

我最好的猜測是這與權限或所有權有關,但這只是我的預感。 我試過在文件上運行chown root:wheel 這將錯誤更改為:

異常代碼78

任何幫助將不勝感激。

編輯來自https://stackoverflow.com/users/2836621/mark-setchell的以下請求

最新的 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>
    <string>com.erithacus.restart</string>
    <key>Program</key>
    <string>/Library/Scripts/com.erithacus.restart.sh</string>
    <key>StandardOutPath</key>
    <string>/tmp/com.erithacus.restart.stdout</string>
    <key>StandardErrorPath</key>
    <string>/tmp/com.erithacus.restart.stderr</string>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>11</integer>
        <key>Minute</key>
        <integer>10</integer>
    </dict>
</dict>
</plist>

最新腳本內容:

#!/bin/bash

/sbin/shutdown -r now >>/tmp/shutdown.log 2&>1

.stdout 文件的內容為空。

.stderr的內容如下: /Library/Scripts/com.erithacus.restart.sh: line 3: 1: Read-only file system

這可能與 macOS Catalina 的操作系統在只讀分區上有關嗎?

編輯 2. 一個解決方案。

最終 plist 文件 (com.erithacus.restart.sh) 內容(盡管必須使用 Xcode 制作):

<?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>
    <string>com.erithacus.restart</string>
    <key>Program</key>
    <string>/Library/Scripts/com.erithacus.restart.sh</string>
    <key>StandardOutPath</key>
    <string>/tmp/com.erithacus.restart.stdout</string>
    <key>StandardErrorPath</key>
    <string>/tmp/com.erithacus.restart.stderr</string>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>12</integer>
        <key>Minute</key>
        <integer>10</integer>
    </dict>
</dict>
</plist>

(顯然更改StartCalendarInterval下的時間以適應)

此 plist 保存在 /Library/LaunchDaemons

最終腳本(com.erithacus.restart.sh):

#!/bin/bash

date +"%F %T Shutting down"

/sbin/shutdown -r now

腳本保存在 /Library/Scripts

關鍵,我認為,與原始文件不同的是,我使用sudo chown root [plist file name]將 plist 文件的所有權更改為root

然后我必須以root身份將它加載到launchctl中,即sudo launchctl load [plist file name] 奇怪的是,當以這種方式加載時,它不會顯示命令launchctl list但如果sudo launchctl list會顯示。

這導致系統成功定時重啟機器,覆蓋任何可能阻止重啟的應用程序。 這對於我想在每天早上 5 點重新啟動的服務器很有幫助(因此顯然 plist 文件中的時間現在將更改為在那個時間運行)。

特別感謝@marksetchell,他的錯誤記錄建議幫助我解決了這個問題。

有幾件事要檢查。


首先,確保您的腳本可以通過以下方式執行:

chmod +x /Library/Scripts/com.apple.restart.sh

其次,將shutdown的完整路徑放入腳本中以確保可以找到它:

#!/bin/bash
/sbin/shutdown -r now

我通過運行發現:

which shutdown

Output

/sbin/shutdown

第三,確保您的腳本是純 ASCII 文本,而不是 RTF 或PagesMS-Word文檔:

file /Library/Scripts/com.apple.restart.sh

Output

/Library/Scripts/com.apple.restart.sh: Bourne-Again shell script text executable, ASCII text

第四,在launchctl之外測試您的腳本,以確保它首先獨立運行:

/Library/Scripts/com.apple.restart.sh

第五,在您的plist文件中像這樣重定向 output:

<key>StandardOutPath</key>
<string>/tmp/com.apple.restart.stdout</string>
<key>StandardErrorPath</key>
<string>/tmp/com.apple.restart.stderr</string>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM