17

有没有办法只在关机时运行脚本?

我的意思是,只有当计算机真正关闭到关闭状态时。仅在注销或重新启动时不应运行此脚本。

4

4 回答 4

27

几天前,我在 github 上发布了一个可以在 boot/shutdown 执行的配置/脚本

基本上在 Mac OS X 上,您可以/应该将System wide and per-user daemon/agent configuration file(plist)与 bash 脚本文件结合使用。这是您可以使用的 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>boot.shutdown.script.name</string>

<key>ProgramArguments</key>
<array>
  <string>SCRIPT_PATH/boot-shutdown.sh</string>
</array>

<key>RunAtLoad</key>
<true/>

<key>StandardOutPath</key>
<string>LOG_PATH/boot-shutdown.log</string>

<key>StandardErrorPath</key>
<string>LOG_PATH/boot-shutdown.err</string>

</dict>
</plist>

您可以将此文件放入/Library/LaunchDaemons. 可以放置plist文件的目录有很多,这取决于你需要什么,进程的权限等等。

~/Library/LaunchAgents         Per-user agents provided by the user.
/Library/LaunchAgents          Per-user agents provided by the administrator.
/Library/LaunchDaemons         System wide daemons provided by the administrator.
/System/Library/LaunchAgents   Mac OS X Per-user agents.
/System/Library/LaunchDaemons  Mac OS X System wide daemons.

该脚本boot-shutdown.sh将在每次启动/关闭时加载和执行。

#!/bin/bash
function shutdown()
{

  # INSERT HERE THE COMMAND YOU WANT EXECUTE AT SHUTDOWN OR SERVICE UNLOAD

  exit 0
}

function startup()
{

  # INSERT HERE THE COMMAND YOU WANT EXECUTE AT STARTUP OR SERVICE LOAD

  tail -f /dev/null &
  wait $!
}

trap shutdown SIGTERM
trap shutdown SIGKILL

startup;

然后调用launchctl加载和卸载守护进程/代理的命令。

sudo launchctl load -w /Library/LaunchDaemons/boot-shutdown-script.plist
于 2014-11-24T10:45:08.360 回答
3

看起来最直接的方法是编写一个小型 C++ 应用程序,该应用程序将作为守护进程使用launchctl运行,捕获关闭通知但忽略重新启动通知(见下文),然后将提供给它的任何内容作为参数调用,例如外壳脚本。Apple 似乎没有提供库来捕捉任何其他语言的通知。

来自 Apple的“内核编程”手册https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/KernelProgramming/KernelProgramming.pdf ,第 150 页:

“虽然 OS X 没有传统的 BSD 风格的关闭钩子,但 I/O Kit 在最近的版本中提供了等效的功能。由于 I/O Kit 提供了此功能,因此您必须从 C++ 代码中调用它。”

“要注册通知,请调用 registerSleepWakeInterest(在 IOKit/RootDomain.h 中描述)并注册睡眠通知。如果系统即将关闭,则使用消息类型 kIOMessageSystemWillPowerOff 调用您的处理程序。如果系统即将关闭重新启动,您的处理程序将获得消息类型 kIOMessageSystemWillRestart。如果系统即将重新启动,您的处理程序将获得消息类型 kIOMessageSystemWillSleep。”

如您所见,有不同的重启消息,因此您可以专门处理关机情况。

于 2014-06-13T10:40:23.740 回答
2

这是一种可行的方法(我只是对其进行了测试),但它非常技术性,不适合没有经验的人......我在/sbin/shutdown 周围放置了一个包装器。即使您从 GUI 中的 Apple 菜单关闭 Mac,这也将起作用。

基本上,您需要su像这样 root,并将现有的 Apple 提供的shutdown二进制文件重命名为shutdown.orig.

su -
cd /sbin
mv shutdown shutdown.orig

然后,您创建一个 bash 脚本shutdown,该脚本首先执行您想要的操作,然后execs是 Apple 提供的原始关闭二进制文件。

#!/bin/bash
Do something you want done before shutdown
exec /sbin/shutdown.orig "$@"

有三点需要注意...

1. Make all the permissions the same on shutdown as shutdown.orig
2. Parse the parameters to the originl shutdown and see if `-r` is one of them as this means it is a `restart` shutdown. You will also have to pass through the other parameters that Apple calls the script with - if any.
3. Apple may feel at liberty to overwrite your lovely, shiny, new `shutdown` script when updating OSX, so maybe abstract out the bulk of your personal shutdown script into another place so that you can easily re-insert a single-line call to it if/when Apple overwrites it at some point.

当心!并先做好备份!

于 2014-06-13T09:54:40.740 回答
0

万一有人像我一样在谷歌上搜索类似但有些不同的问题。

由于我发现https://github.com/hluk/CopyQ/issues/1301的 CopyQ 崩溃错误,我 不得不编写一个 cron 脚本,如果它崩溃,它将重新加载。但我不想重新加载 copyq,如果 copyq 在关机或重启期间退出

我最终使用

if ps aux | grep "Finder.app" | grep -v grep
then
    echo "I am still running"
else
    echo "I am in shutdown"
fi

要检测系统是否处于关闭状态,(您可以Chrome.app根据需要使用或任何其他始终运行的应用程序)

不完全是解决方案,但帮助我解决了我遇到的类似问题

于 2021-04-02T05:45:39.033 回答