仅在Mac OS X上关机(不注销或重启)时运行脚本

时间:2014-06-13 08:30:51

标签: macos bash shell shutdown-hook system-shutdown

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

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

4 个答案:

答案 0 :(得分:16)

几天前我在github上发表了configuration/script able to be executed at 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

答案 1 :(得分:3)

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

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

su -
cd /sbin
mv shutdown shutdown.orig

然后创建一个名为shutdown的bash脚本,它首先执行您想要的操作,然后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.

小心!并先备份!

答案 2 :(得分:3)

看起来最直接的方法是编写一个小型C ++应用程序,该应用程序将作为带有 launchctl 的守护程序运行,捕获关闭通知但忽略重新启动通知(见下文),然后调用无论作为论据给予什么,例如一个shell脚本。它看起来并不像Apple提供库来捕获任何其他语言的通知。

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

&#34;虽然OS X没有传统的BSD式关闭挂钩,但I / O Kit在最新版本中提供了相同的功能。由于I / O Kit提供此功能,因此必须从C ++代码中调用它。&#34;

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

正如您所看到的,重新启动时会有不同的消息,因此您可以专门处理关闭案例。

答案 3 :(得分:0)

如果有人像我一样通过谷歌搜索类似但有些不同的问题来回答这个问题。

由于我发现的 CopyQ 崩溃错误 https://github.com/hluk/CopyQ/issues/1301 我必须编写一个 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 或任何其他始终运行的应用程序)

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