Wi-Fiの接続先が変化した際にシェルスクリプトを走らせる(Mac OSX)
すごく稀なユースケースだと思うんですが、
例えば研究室の無線LANに接続しているときだけプロキシ設定を有効にし、それ以外のときは無効にしたい場合を考えます。
通常であれば、研究室のWi-Fiに繋いだら
export http_proxy="http://www-proxy.waseda.jp:8080" export HTTPS_PROXY="http://www-proxy.waseda.jp:8080"
で環境変数の設定をして、家に戻ったら
unset http_proxy HTTPS_PROXY
で環境変数をリセットさせる。
このようなことを何度も繰り返します。
でも、間違いなくめんどうです!
そこで、接続先の無線LANが変化した(異なるSSIDのネットワークに接続した)際に、プロキシ設定を更新することを考えます。
1. シェルの hook を考える
通常、特定のシェルスクリプトを何度も走らせたい場合、cronを用いることが一般的だと思いますが、
今回は、特定のイベントがおこなわれた際に発火する hook を使ってみます。
シェルの hook については、こちらのサイトが詳しく説明してくれていました。
大変ありがたかったです。
シェルでコマンドの実行前後をフックする - Hibariya ( http://note.hibariya.org/articles/20170219/shell-postexec.html )
hook の種類は少ないですが、
そこは if 文でがんばるとして、
preexec という、シェルに入力したコマンドが実行される直前に発火されるというこの hook を使ってみましょう。
2. 接続中の SSID を取得する
ここのサイトで知りました。
https://stackoverflow.com/questions/4481005/get-wireless-ssid-through-shell-script-on-mac-os-x
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk '/ SSID/ {print substr($0, index($0, $2))}'
これを実行すると、たしかに現在接続中のSSID名称が出てきます。すごい。
SSID取得の方法がわかったので、この値を環境変数として記録しておいて、
次回呼び出したときに、前回のSSIDと変わっているのかを確認すれば良さそうです。
SSIDが変更されたかの条件分岐を最初におこなうことで、
コマンド実行ごとに発火されるこの hook によるシェルへの負荷を、できるだけ少なくしてあげることが出来ます。
3. できあがるスクリプト例
上の 1. , 2. を参考にすると、例えば以下のようなスクリプトが出来上がります。
zshとbashに対応させました。(bashの方は検証が足りていないので、もしかすると上手く動かないかも…)
# Check if SSID is changed, and update proxies function check_ssid() { local -r LABO_PROXY="http://www-proxy.waseda.jp:8080" local previous_ssid="$CURRENT_SSID" local current_ssid=$(/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk '/ SSID/ {print substr($0, index($0, $2))}') export CURRENT_SSID="$current_ssid" if [ "$previous_ssid" != "$current_ssid" ] ; then case "$current_ssid" in "ssid_of_labo") # SSID of your labo's network export http_proxy="$LABO_PROXY" export HTTPS_PROXY="$LABO_PROXY" ;; *) unset http_proxy HTTPS_PROXY ;; esac fi } function add_shell_hook() { local shell_pid=$$ if ps -p $shell_pid | grep -qs "zsh" ; then autoload -Uz add-zsh-hook add-zsh-hook preexec check_ssid elif ps -p $shell_pid | grep -qs "bash" ; then local -r BASH_PREEXEC_PATH="${HOME}/.bash-preexec.sh" if [ ! -e $BASH_PREEXEC_PATH ]; then curl -s https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o $BASH_PREEXEC_PATH fi source $BASH_PREEXEC_PATH preexec() { check_ssid; } else echo "Error: This script supports only zsh and bash." 1>&2 fi } add_shell_hook
これを ~/.zshrc
(もしくは ~/.bashrc
)に直書きするか、
もしくはシェルスクリプトに記述して、 ~/.zshrc
( ~/.bashrc
) から source
コマンドで呼び出すようにすれば、hook が登録され、
SSID が変わるごとにプロキシ設定が更新されるようになります。
もちろん、 LABO_PROXY
や "ssid_of_labo"
の値は適当に変えてくださいね。
4. 注意点
私のハマったところとして、
このシェルスクリプト内で export CURRENT_SSID="$current_ssid"
と export している箇所がありますが、
単純なシェルスクリプトとして実行させていたときは CURRENT_SSID が環境変数として保存されず悩んでいました。
【追記あり】シェルスクリプト内でexportした環境変数は実行後でも使えるのか - by shigemk2 ( https://www.shigemk2.com/entry/linux_shell_export_path )
これによると、
ということでとても合点がいきました。
スクリプトを使って現在の shell に環境変数を読み込ませるためには、
.zshrc に直接書くなり、 source コマンドで呼び出すなりしないといけないのですね。
5. まとめ
以上、shell の hook 機能と、
SSIDを取得できることを利用したプチハックでした。
これの延長線上で、いろいろ便利なことができそうな気がします。
以下に、より細かい設定を加えたバージョンの gist を貼っておきます。ご参考にどうぞ。