スクリプトで無線LANにWi-Fi接続する　-Mac編-


Wi-Fiダイレクトで直接デバイスに無線接続するときに、毎回メニューバーから選ぶのが面倒なので作りました。
Yosemite 10.10.5で動作確認済みです。

```bash:wificonn_mac.sh
#!/bin/bash
set -u
export LANG="C"

function usage() {
  cat <<EOT
Usage: bash ${0##*/} <network-SSID> <password>
EOT
}

# 引数チェック
if [ $# -ne 2 ]; then usage && exit 1; fi

# Wi-Fiのデバイス名を調べる
WIFI_DEV_NAME=$(networksetup -listallhardwareports | grep -w Wi-Fi -A1 | awk '/^Device:/{ print $2 }')
if [ -z "${WIFI_DEV_NAME}" ]; then
  echo "Wi-Fi device not found!"
  exit 2
fi

# すでに接続されていれば終了
networksetup -getairportnetwork ${WIFI_DEV_NAME} | grep -wq $1
if [ $? -eq 0 ]; then
  echo 'Already connected.'
  exit 0
fi

POWER_ON_WAIT=1
# Wi-Fiの電源が入ってなければ入れる
networksetup -getairportpower ${WIFI_DEV_NAME} | grep -wiq 'off'
if [ $? -eq 0 ]; then
  networksetup -setairportpower ${WIFI_DEV_NAME} on
  if [ $? -ne 0 ]; then
    echo "Failed to power on ${WIFI_DEV_NAME}."
    exit 3
  fi
  sleep ${POWER_ON_WAIT}
fi

# airportコマンドのフルパス
AIRPORT_CMD='/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport'
# 指定のSSIDを持つアクセスポイントがあるか調べる
${AIRPORT_CMD} --scan=$1 | grep -wq $1
if [ $? -ne 0 ]; then
  echo "The wi-fi network with SSID:'$1' not found."
  exit 4
fi

# 接続リトライ回数/リトライ間隔秒数
CONNECTION_RETRY=3
RETRY_INTERNAL=2
# 接続する
remain=${CONNECTION_RETRY}
while [ ${remain} -gt  0 ]
do
  # networksetup -setairportnetwork は成功時も失敗時も0を返してくるので出力で判断
  networksetup -setairportnetwork ${WIFI_DEV_NAME} $1 $2 | grep -wq 'Error'
  if [ $? -ne 0 ]; then
    break
  fi
  ((remain--))
  sleep ${RETRY_INTERNAL}
done
if [ ${remain} -eq 0 ]; then
  echo "Failed to join the network. Password may be incorrect."
  exit 5
fi

# 接続されているか念のため確認
networksetup -getairportnetwork ${WIFI_DEV_NAME} | grep -wq $1
if [ $? -ne 0 ]; then
  echo 'Something wrong occured!'
  exit 6
fi

echo 'Connected successfully.'
exit 0
```

## 使い方

```bash
$ bash wificonn_mac.sh <network-SSID> <password>
```

生でパスワードを打つので、共同のマシンでは注意してください。
aliasとか設定してやると幸せになれるかもしれません。

## 一応解説

Macでコマンドラインからネットワーク接続を設定するには`networksetup`コマンドを使います。
`networksetup`には多様なサブコマンドが付属しており（数えたら119個もありました）、Wi-FiだけでなくBluetoothやThunderboltの設定もできるようです。
今回は以下のコマンドを使用しました。

| コマンド                                                           | 用途                                |
|--------------------------------------------------------------------|-------------------------------------|
| `networksetup -listallhardwareports`                                 | 全ネットワークデバイスを表示        |
| `networksetup -getairportpower <device name>`                        | `<device name>`の電源のON/OFFを調べる |
| `networksetup -setairportpower <on off>`                            | `<device name>`の電源をON/OFFする       |
| `networksetup -getairportnetwork <device name>`                      | `<device name>`の接続されているネットワークを表示する |
| `networksetup -setairportnetwork <device name> <network> [password]` | `<device name>`をパスワード=`password`でSSID=`network`のネットワークに接続する |

無線ネットワークの検索（スキャン）は`networksetup`からはできず、代わりに`airport`コマンドを使用します。しかし、何故か`airport`コマンドにはパスが通っておらず、
`/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport`という長い長いフルパスで呼びだす必要があります。
今回は`--scan=<network-SSID>`として検索対象のネットワークを指定しましたが、単に`--scan`とすれば周囲の全てのネットワークの検索結果を返します。接続したいネットワークが複数ある場合はオプション無しで実行すると良いでしょう。