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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24200924/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 10:40:13  来源:igfitidea点击:

Run a script only at shutdown (not log off or restart) on Mac OS X

macosbashshellshutdown-hooksystem-shutdown

提问by Audio01

Is there any way to run a script only at shutdown?

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

I mean, only when the computer is really shutting down to off state. This script should not run when doing just a log off or restart.

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

回答by freedev

Few days ago I published on github a configuration/script able to be executed at boot/shutdown.

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

Basically on Mac OS X you could/should use a System wide and per-user daemon/agent configuration file(plist)in conjunction with a bash script file. This is a sample of the plist file you could use:

基本上在 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>

You can place this file into /Library/LaunchDaemons. There are many directories where the plist file could be placed, it depends from what you need, the rights of the process and so on.

您可以将此文件放入/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.

This script boot-shutdown.shwill be loaded and executed at every boot/shutdown.

该脚本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;

Then call launchctlcommand which load and unload daemons/agents.

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

sudo launchctl load -w /Library/LaunchDaemons/boot-shutdown-script.plist

回答by Oleg Sklyar

It looks like the most straightforward way would be to write a small C++ application that would run as a daemon with launchctl, catch the shutdown notification but ignore the reboot notification (see below) and then call whatever is given to it as arguments, e.g. a shell script. It does not look like Apple provides libraries to catch those notifications in any other language.

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

From the "Kernel Programming" manual https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/KernelProgramming/KernelProgramming.pdffrom Apple, page 150:

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

"Although OS X does not have traditional BSD-style shutdown hooks, the I/O Kit provides equivalent functionality in recent versions. Since the I/O Kit provides this functionality, you must call it from C++ code."

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

"To register for notification, you call registerSleepWakeInterest (described in IOKit/RootDomain.h) and register for sleep notification. If the system is about to be shut down, your handler is called with the message type kIOMessageSystemWillPowerOff. If the system is about to reboot, your handler gets the message type kIOMessageSystemWillRestart. If the system is about to reboot, your handler gets the message type kIOMessageSystemWillSleep."

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

As you can see there is a different message for reboot, so you can handle the shutdown case exclusively.

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

回答by Mark Setchell

Here is a way that does work (I just tested it) but it is quite technical and not for inexperienced people... I put a wrapper around /sbin/shutdown. This will work even if you shutdown your Mac from the Apple menu in the GUI.

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

Basically, you need to suto root, like this, and rename the existing, Apple-supplied shutdownbinary to shutdown.orig.

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

su -
cd /sbin
mv shutdown shutdown.orig

Then you create a bash script called shutdownthat does what you want first, then execsthe original Apple-supplied shutdown binary.

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

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

There are three things to watch out for...

有以下三点需要注意...

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.

Be careful! And make a backup first!

当心!并先进行备份!