Linux和Unix系統一直很容易在啓動時執行命令,只需要將你的命令添加到 /etc/rc.local 文件中。但事實證明,在關機時運行命令有點複雜。
你爲什麼想要在計算機關閉時運行命令呢?也許你想從數據庫去註冊一個機器或服務,也許你想將數據從一個易失性存儲系統複製到一個永久的位置(比如將內存中的數據寫入到硬盤中去),或者想要你的電腦在它關機前在它的Twitter賬戶上發佈"#RIP me!"
我需要澄清一點,我說的是所謂的“一次性”命令而不是停止守護進程。儘管把他們想象成一樣是誘人的。如果你熟悉SysVinit,你可能會想“哦,我能直接創建一個Kill腳本”。例如,當你的系統在運行級別3退出時/ etc / rc.d/rc3.d/k99runmycommandatshutdown會調用。畢竟這就是/etc/init.d/中的腳本如何停止的。
這是一個膩害的猜測,然而事實證明這是錯誤的。SysVinit並不盲目運行Kill腳本。相反,它 (RedHat 6)會在 /var/lock/subsys/service_name (此處的service_name假設爲runmycommandatshutdown)中查找可執行的相關命令。所以你可能會在讓系統將你的腳本當作普通服務上遇到一些麻煩。下面的腳本給出了一個例子:
#!/bin/sh # chkconfig: 2345 20 80 # description: An example init script to run a command at shutdown # runmycommandatshutdown runs a command at shutdown. Very creative. LOCKFILE=/var/lock/subsys/ start(){ # Touch our lock file so that stopping will work correctly touch ${LOCKFILE} } stop(){ # Remove our lock file rm ${LOCKFILE} # Run that command that we wanted to run mycommand } case "$1" in start) start;; stop) stop;; *) echo $"Usage: $0 {start|stop}" exit 1 esac exit 0
之後將這個腳本放到 /etc/init.d/runmycommandatshutdown 中,然後 chkconfig on runmycommandatshutdown 使其可用,你的命令就會在關機時運行。
在Slackware (sysvinit in BSD compatible mode)中更容易實現:
$ cat /etc/rc.d/rc.local_shutdown #!/bin/sh # # /etc/rc.d/rc.local_shutdown: Local system shutdown script. # # Put any local shutdown commands in here. my_command_at_shutdown exit 0 $ sudo chmod +x /etc/rc.d/rc.local_shutdown
對於systemd
這一切都很不錯,但是如果你運行的Linux版本使用Systemd而不是SysVinit呢?實際上在Systemd中更簡單。你所要做的就是將你的腳本放到由systemd-halt.service所管理的 /usr/lib/systemd/system-shutdown/ 目錄中去。當然,如果你需要在一個特定的情況下去管理依賴關係(例如你無法在沒網的情況下發推特),這時你可以寫一個系統服務組文件。例如:
[Unit] Description=Run mycommand at shutdown Requires=network.target DefaultDependencies=no Before=shutdown.target reboot.target [Service] Type=oneshot RemainAfterExit=true ExecStart=/bin/true ExecStop=mycommand [Install] WantedBy=multi-user.target
補充:Shutdown Sequence Systemd
1.首先創建一個觸發服務(該服務需要是關機服務)
# cat /lib/systemd/system/fakehalt.service [Unit] Description=Fake-Halt Service After=fakevm.service Requires=fakevm.service [Service] Type=simple ExecStart=/usr/local/bin/fakehalt.sh #this will fail until fakevm succeeds ExecReload=/usr/local/bin/fakehalt.sh
2.然後創建一個系統允許的你想要在關機之前運行完成的命令文件
# cat /lib/systemd/system/fake.service [Unit] Description=Fake Service Before=fakehalt.service [Service] Type=simple ExecStart=/usr/local/bin/fake.sh
3.創建一個腳本來表示虛擬機關機(或任何你不能預見其持續時間的進程)
# cat /usr/local/bin/fake.sh #!/bin/sh test="1" sleep 21 if [ X"$test" = "X1" ]; then echo "vm has shut down" > /tmp/fake.test exit 0 else exit 1 fi
和一個用於關閉信號的腳本:
# cat /usr/local/bin/fakehalt.sh #!/bin/sh sleep 3 cat /tmp/vmfake.test > /tmp/haltfake.test
4.啓動
# systemctl start fakehalt
有可能fakehalt找不到一個叫 /tmp/fake.test 的文件,然後一切都亂套了。實際情況是系統會保持 fakehalt 服務運行直到收到了 exit 0 信號。因此如果你在fakehalt開始後等21秒之後cat /tmp/fakehalt.test ,你會發現/tmp/fakehalt.test並不存在,因爲fakehalt已經成功執行了。