【发布时间】:2020-11-20 00:06:21
【问题描述】:
我正在尝试让脚本每天同时运行以重新启动 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,他的错误记录建议帮助我解决了这个问题。
【问题讨论】:
-
脚本在哪个账户下运行?可以添加调试吗? (如
shutdown -r now >>/tmp/shutdown.log并确保运行脚本的用户对该文件具有写入权限。) -
另外,您自己的脚本可能看起来不应该属于
com.apple -
谢谢,我会试一试的。我尝试了各种名称,并且在某处我读到有人说要尝试。同意,这很奇怪。将尝试再次将其更改为其他内容。我对 launchd 的理解是它们由系统以 root 身份运行,所以我不确定用户是否相关?至少,我正在尝试达成一种用户不重要的安排,并且无论如何它都会运行。
-
我会想象它以 root 身份运行,但不应该出现错误,所以这就是我在这一点上的推测。我认为
launchd可以指定以哪个用户身份运行。 -
哦,当然还有重定向标准错误,否则日志可能是空的。
shutdown -r now >>/tmp/shutdown.log 2&>1... 很抱歉没有提到这一点。
标签: bash macos sh restart launchd