Windows で VirtualBox を使っている方にはわかるかもしれないのですが、普段の業務終了時に VM を終了せずに PC をシャットダウンしようとして↓のようなメッセージが表示されたことはないですか?
VirtualBox Interface
このアプリがシャットダウンを妨げています。
私もこれが出ると「うわ・・・またやっちまった・・・」となります
そして一旦デスクトップに戻りタスクマネージャを開き VirtualBox Interface
を終了し・・・
せっかく早く帰れると思ったのに
今回は、そんなお悩みをシェルスクリプトで解決してみようと思います
対策?
対策は簡単です
ズバリ、
PC をシャットダウンする前に VM をすべて終了する
です
というか、これを忘れてしまうから困っているわけなんですが
シャットダウンのコマンドを用意しよう
Windows のシャットダウンはコマンドで実行することができます。
shutdown -s -t 0
-s
はシャットダウン、 -t 0
は処理が行われるまでの時間(秒)を表しています。
この例の場合だと、「0 秒経ったらシャットダウン」、つまり即時シャットダウンのことを意味しています。
シャットダウンコマンドについては こちらの記事 を参考にさせていただきました。
起動中の VM をすべて終了するコマンドを用意しよう
VirtualBox には VM の操作をコマンドラインで行える VBoxManage
が用意されています。
これを利用して、起動中の VM を一覧で表示し、それをシャットダウンの引数に渡すようにします。
なお、 bash: VBoxManage: command not found
になるよという方は、 VBoxManage
を環境変数に登録してください。
VBoxManage
の場所に関しては 【VirtualBox】VBoxManageを使う - Qiita が参考になるかと思います。
VBoxManage list runningvms | cut -d' ' -f1 | xargs -I{} VBoxManage controlvm {} acpipowerbutton
なお、 VBoxManage のコマンドについては Virtualboxの仮想マシンをコマンドラインから操作 - Qiita を参考にさせていただきました。
スクリプトを完成させよう
必要なコマンドはそろいましたので、いよいよスクリプトを作っていこうと思います。
方針は簡単で、起動中の VM をすべて終了してから Windows をシャットダウンさせるだけなのですが、落とし穴が一つあります。
VM を終了するコマンドは、 VM のシャットダウンシグナルを送るのみですぐに処理が終わり、 VM のシャットダウンを待ちません。
なので、上記 2 つのコマンドをそのまま並べて実行すると、また VM が終了しないまま PC のシャットダウンに入ってしまいます
これを回避するために、起動中の VM の一覧を定期的にコマンドで確認し、出力がなくなってから PC のシャットダウンに入るような処理を記述します。
#!/usr/bin/env bash
INTERVAL=3 # 起動中の VM 一覧を確認する周期
VBoxManage list runningvms | cut -d' ' -f1 | xargs -I{} VBoxManage controlvm {} acpipowerbutton
while [ $(VBoxManage list runningvms | wc -l) -ne 0 ]
do
echo "shutting down VMs..."
sleep ${INTERVAL}
done
そして、シャットダウン時に実行するファイルを作成します。
#!/usr/bin/env bash
./shutdown_vms.sh
wait
echo "bye"
sleep 1
shutdown -s -t 0
これで完成です
動作確認しよう
- VM をいくつか立ち上げておきます。
- 上で作成した
shutdown_vms.sh
とshutdown_entrypoint.sh
を同じディレクトリに配置します。 - エクスプローラの画面で
shutdown_entrypoint.sh
をダブルクリック、あるいは Git Bash で./shutdown_entrypoint.sh
を実行します。
こんな感じで出力されていたらうまくいっています
shutting down VMs...
shutting down VMs...
shutting down VMs...
bye
みなさんも身の回りの面倒なことを自動化して快適に開発し、快適におうちに帰りましょう