macOS Launchd 啟動任務(wù)

macOS 通過啟動硬盤指定目錄下的配置文件,來完成啟動任務(wù)。這些文件為plist,本質(zhì)上是XML。

0x00 Launchd 目錄配置

Mac下Launchd的plist文件放置的目錄有

由用戶自己定義的任務(wù)項
~/Library/LaunchAgents        
          
由管理員為用戶定義的任務(wù)項
/Library/LaunchAgents                    

由管理員定義的守護進程任務(wù)項
/Library/LaunchDaemons             

由 macOS 為用戶定義的任務(wù)項
/System/Library/LaunchAgents 
      
由 macOS 定義的守護進程任務(wù)項
/System/Library/LaunchDaemons 

其中 LaunchDaemons 和 LaunchAgents 的區(qū)別是什么?

  • LaunchDaemons 是用戶未登陸前就啟動的服務(wù)(守護進程)需要 root 權(quán)限, 即 sudo xx
  • LaunchAgents 是用戶登陸后啟動的服務(wù)(守護進程)

0x01 Launchd Plist 配置

標簽 必填 說明
Label 標識符,用來表示該任務(wù)的唯一性
Program 程序名稱,用來說明運行哪個程序、腳本
ProgramArguments 同上,與Program二選一或一起使用,只是可以運行多個程序、可帶參數(shù)
WatchPaths 監(jiān)控路徑,當路徑文件有變化是運行程序,也是數(shù)組
RunAtLoad 是否在加載的同時啟動
StartCalendarInterval 運行的時間,單個時間點使用dict,多個時間點使用 array -> dict
StartInterval 時間間隔,與StartCalendarInterval使用其一,單位為秒
StandardInPath、StandardOutPath、StandardErrorPath 標準的輸入輸出錯誤文件,這里建議不要使用.log作為后綴,會打不開里面的信息

兩種指定要執(zhí)行命令的方法:

使用 Program 和 ProgramArguments

  • Program, 運行命令或要執(zhí)行文件路徑
  • ProgramArguments, 執(zhí)行時傳入?yún)?shù)

只使用 ProgramArguments

  • ProgramArguments 的每個參數(shù)為要執(zhí)行的命令或文件路徑,其它參數(shù)為傳入?yún)?shù)

兩種設(shè)置執(zhí)行時間的方法:

  • StartCalendarInterval 使用元素Minute, Hour, Day, Month, Weekday指定執(zhí)行時間,如:
<!-- 每天的9:30執(zhí)行 -->
<key>StartCalendarInterval</key>
<dict>
  <key>Minute</key>
  <integer>30</integer>
  <key>Hour</key>
  <integer>9</integer>
</dict>
  • StartInterval 設(shè)置執(zhí)行的時間間隔,單位為秒
<!-- 每小時執(zhí)行一次 -->
<key>StartInterval</key>
<integer>3600</integer>

0x02 Launchd 定時任務(wù)

編寫我的 shell 腳本文件

功能是在 macOS 開機后自動執(zhí)行下面的腳本, 開啟內(nèi)網(wǎng)穿透的功能, 可以忽略我的腳本內(nèi)容, 替換成你想用的腳本

# launch.sh
#! /bin/bash

export ZWY_HOME=/Users/mb
export ZWY_DIR=$ZWY_HOME/ZwyShell
export ZWY_DIR_FeiGeNAT=$ZWY_HOME/ZwyShell/darwin_amd64_client
export PATH=$PATH:$ZWY_DIR:$ZWY_DIR_FeiGeNAT

LOG_PATH=$ZWY_DIR/launch/launch.log

echo "====start zwy launch====" >> $LOG_PATH

echo $(date +"%Y-%m-%d %H:%M:%S") >> $LOG_PATH
echo "npc is in "`which npc` >> $LOG_PATH

npc -server=nps.xxxx.press:8024 -vkey=zwy -type=tcp > $ZWY_DIR_FeiGeNAT/npc_home.log

注意:
可以使用 chmod a+x launch.sh 給權(quán)限變成可執(zhí)行文件, 也可以用 bash 命令調(diào)用

編寫 Plist 文件

~/Downloads 下面創(chuàng)建一個 Plist 文件, 都寫好后, 再復(fù)制到想要的權(quán)限文件夾下面

<?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.zwy.home</string>
    <key>ProgramArguments</key>
    <array>
        <string>bash</string>
        <string>/Users/mb/ZwyShell/launch/launch.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>Version</key>
    <string>3</string>
</dict>
</plist>

可以用 plutil -lint com.zwy.home.plist 來驗證 Plist 格式是否正確

加載命令

launchctl 是一個統(tǒng)一的服務(wù)管理框架,啟動、停止和管理守護進程、應(yīng)用程序、進程和腳本


# 加載任務(wù), -w選項會將plist文件中無效的key覆蓋掉,建議加上
launchctl load -w com.zwy.home.plist
launchctl start com.zwy.home

# 刪除任務(wù)
launchctl stop com.zwy.home.plist
launchctl unload -w com.zwy.home

# 查看任務(wù)列表, 使用 grep '任務(wù)部分名字' 過濾
launchctl list | grep 'com.zwy.home.plist'

經(jīng)驗

如果執(zhí)行 launchctl load 命令出現(xiàn) com.zwy.home.plist: Path had bad ownership/permissions,需要為 plist 文件賦予600 權(quán)限或者 root 權(quán)限, 都可以嘗試一下:

sudo chmod 600 path/com.zwy.home.plist

sudo chown root:wheel path/com.zwy.home.plist

執(zhí)行 launchctl list 查看到你的執(zhí)行結(jié)果, 其他錯誤可以用 launchctl error <insert numerical error code here>來查看具體錯誤:

$ launchctl list | grep 'com.zwy.home'
-    78    com.zwy.home # 錯誤結(jié)果
-    0      com.zwy.home # 正確結(jié)果

執(zhí)行 launchctl list 具體描述如下:

1230    -   com.apple.speech.speechsynthesisd
353     -   com.apple.security.cloudkeychainproxy3
255     -   com.apple.secd
-       0   com.apple.sbd

第一列表示進程號,如果有在結(jié)果中羅列,但沒有數(shù)字而只是一個橫線,標志雖然已經(jīng)loaded, 但沒有運行
第二列是上次退出的狀態(tài)號(the last exit code), 0表示成功,正數(shù)表示錯誤退出,負數(shù)表示收到信號后退出

如果 shell腳本輸出如果有中文,中文部分亂碼,則需要在shell腳本中指定編碼:

#!/bin/bash

LANG=en_US.UTF-8
export LANG

echo "你好賈維斯"

2024-07-10 補充
有時候會遇到 exit code 為 1, 表示沒有權(quán)限, 在我的這里, 實際上是 bash 沒有權(quán)限訪問磁盤文件, 在系統(tǒng)設(shè)置里添加自己的 bash 為完全磁盤訪問權(quán)限即可, 查看 bash 在哪里, 用 which bash

2025-03-12 補充
遇到了 exit code 126 表示沒有磁盤權(quán)限, 我放到了 /Documents 下, 用 bash 執(zhí)行了命令, 解決這個需要給 bash 完全磁盤權(quán)限

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容