【问题标题】:Run a script only at shutdown (not log off or restart) on Mac OS X在 Mac OS X 上仅在关机时(不注销或重新启动)运行脚本
【发布时间】:2014-08-03 18:05:20
【问题描述】:

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

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

【问题讨论】:

  • 您是否有适用于关机和重启的解决方案?在这种情况下,问题将是检测脚本中的重新启动...
  • 我可以请您选择我的答案更正确吗?

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


【解决方案1】:

前几天我在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

【讨论】:

  • 它在 el capitan 上运行良好。但是我的 xcode7 在 el capitan 上崩溃了,然后我回到优胜美地,脚本在优胜美地上不起作用。我必须使用 LogoutHook 来运行关机功能。
  • 它不适用于 el-capitan 上的关机它仅适用于启动,我错过了什么
  • 尝试在此处发布您的问题github.com/freedev/macosx-script-boot-shutdown
  • 你可能宁愿这样做而不是 tail -f /dev/null : mkfifo /tmp/wait-fifo;阅读
【解决方案2】:

看起来最直接的方法是编写一个小型 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。"

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

【讨论】:

  • 这将是完成它的简洁方式,但要复杂得多。
  • 从我的回答之日起两年内,我建议代替 C++ 让事情变得更简单......
  • @olegsklyar,您好,我尝试从驱动程序使用此注册,但似乎我的回调函数没有在 ShotDown 和 Restart 事件中调用,也许您也遇到过类似的问题?
【解决方案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.

小心!并先做好备份!

【讨论】:

  • 这是实现它的肮脏方式,在封闭的“受控”环境(即没有更新)中它应该可以正常工作。
  • @Audi01 脏?肮脏的?我更喜欢“稍微未洗但有效”:-)
  • 当 El Capitan 发布时,这将不再有效。 shutdown/sbin 中,受 rootless 保护。
  • @TheBleacher Aha - 所以第 3 点已经实现了!谢谢你的更新。能否提供一些链接供大家参考和理解?
  • 恐怕目前缺少文档。我唯一能找到的:系统完整性保护,也称为“无根”,是一种新的系统安全功能,可防止用户或任何进程写入受系统保护的文件夹。此列表包括 /System、/bin、/usr(但不包括 /usr/local)和 /sbin。 (来自:arstechnica.com/apple/2015/06/…
【解决方案4】:

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

由于我发现 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 或任何其他始终运行的应用程序)

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

【讨论】:

  • 专业提示 -- 不需要 grep -v: ps aux | grep "[F]inder.app"
猜你喜欢
  • 2016-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 2011-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多