IPアドレスを調べるシンプルなシェルスクリプト(IPv6も対応)

# 能書きは後にして、とりあえず答えはこれ。

今そのホストが持っている、グローバルIPアドレスだけを取得する。(無ければ一つも表示されない) 一応、FreeBSD 9.1RとCentOS 5.5で動作確認をしてある。

```sh:IPv4版
/sbin/ifconfig -a                                 | # ifconfigコマンド実行
grep inet[^6]                                     | # IPv4アドレスの行を抽出
sed 's/.*inet[^6][^0-9]*\([0-9.]*\)[^0-9]*.*/\1/' | # IPv4アドレス文字列だけ抽出
grep -v '^127\.'                                  | # lookbackを除去
grep -v '^10\.'                                   | # private(classA)除去
grep -v '^172\.\(1[6-9]\|2[0-9]\|3[01]\)\.'       | # private(classB)除去
grep -v '^192\.168\.'                             | # private(classC)除去
grep -v '^169\.254\.'                               # link local除去
```

```sh:IPv6版
/sbin/ifconfig -a                                          | # ifconfigコマンドを実行
grep inet6                                                 | # IPv6アドレスの行を抽出
sed 's/.*[[:blank:]]\([0-9A-Fa-f:]*:[0-9A-Fa-f:]*\).*/\1/' | # IPv6アドレス文字列抽出
grep -v  '^::1$'                                           | # loopback(略記)を除去
grep -v  '^\(0\+:\)\{7\}0*1$'                              | # loopbackを除去
grep -vi '^fd00:'                                          | # private(既に廃止)を除去
grep -vi '^fe80:'                                            # link local除去
```

ifconfigの出力を、ループ文とif文などを使って1つ1つパースするようなコードを書くと長く複雑になりがち。でもパイプと複数のコマンドを駆使すれば、短く、わかりやすくなる。 **パイプを使えば「スモール・イズ・ビューティフル」!**

# シェル変数で受け取りたい場合は？

方法は2つある。そうそう、 **得られるIPアドレスは1つとは限らないので注意** すること。

## その1. 全体を`$(～)`で囲むやり方。

方法その1は、全体を`$(～)`で囲み、サブシェル化してしまうというもの。

```sh:IPアドレスをシェル変数に入れる方法その1
ipv4addrs=$(/sbin/ifconfig -a                                 |
            grep inet[^6]                                     |
            sed 's/.*inet[^6][^0-9]*\([0-9.]*\)[^0-9]*.*/\1/' |
            grep -v '^127\.'                                  |
            grep -v '^10\.'                                   |
            grep -v '^172\.\(1[6-9]\|2[0-9]\|3[01]\)\.'       |
            grep -v '^192\.168\.'                             |
            grep -v '^169\.254\.'                             )
for ipv4addr in $ipv4addrs; do
  # 何らかの処理 (例↓)
  ping -c 1 $ipv4addr >/dev/null
  [ $? -eq 0 ] || echo "$ipv4addr is not alive!" 1>&2
done

ipv6addrs=$(/sbin/ifconfig -a                                          |
            grep inet6                                                 |
            sed 's/.*[[:blank:]]\([0-9A-Fa-f:]*:[0-9A-Fa-f:]*\).*/\1/' |
            grep -v  '^::1$'                                           |
            grep -v  '^\(0\+:\)\{7\}0*1$'                              |
            grep -vi '^fd00:'                                          |
            grep -vi '^fe80:'                                          )
for ipv6addr in $ipv6addrs; do
  # 何らかの処理 (例↓)
  ping6 -c 1 $ipv6addr >/dev/null
  [ $? -eq 0 ] || echo "$ipv6addr is not alive!" 1>&2
done
```

## その2. シェル関数にしてしまう

あちこちで使い回したい場合はやっぱり関数化するのがいいかなぁ……。関数化したら同じくそれを`$(～)`で囲めばシェル変数に代入できる。

次の例では、たたシェル変数に入れるだけでは面白くないので、さらに別のコマンドにパイプで繋いでみている。

```sh:IPアドレスをシェル変数に入れる方法その2
get_ipv4addrs() {
  /sbin/ifconfig -a                                 |
  grep inet[^6]                                     |
  sed 's/.*inet[^6][^0-9]*\([0-9.]*\)[^0-9]*.*/\1/' |
  grep -v '^127\.'                                  |
  grep -v '^10\.'                                   |
  grep -v '^172\.\(1[6-9]\|2[0-9]\|3[01]\)\.'       |
  grep -v '^192\.168\.'                             |
  grep -v '^169\.254\.'
}

get_ipv6addrs() {
  /sbin/ifconfig -a                                          |
  grep inet6                                                 |
  sed 's/.*[[:blank:]]\([0-9A-Fa-f:]*:[0-9A-Fa-f:]*\).*/\1/' |
  grep -v  '^::1$'                                           |
  grep -v  '^\(0\+:\)\{7\}0*1$'                              |
  grep -vi '^fd00:'                                          |
  grep -vi '^fe80:'
}

num_ipv4=$(get_ipv4addrs | wc -l)
num_ipv6=$(get_ipv6addrs | wc -l)
echo "現在持っているグローバルIPv4アドレスの数:" $num_ipv4
echo "現在持っているグローバルIPv6アドレスの数:" $num_ipv6
```

# 補足

## ifconfigコマンドを絶対パスにしている理由

ifconfigコマンドを絶対パス決め打ちにしているのは、Linuxで使う場合の対策。このコマンドは大抵/sbinの中にあるが、多くのLinux上では一般ユーザーにifconfigコマンドのパスが通っていないため決め打ちにしてある。もし、/sbinには無いかもしれない環境も考慮するのであれば、環境変数PATHに、`/sbin`、`/usr/sbin`、`/etc`あたりを追加しておくとよいだろう。 **（`/etc`に置いてあるOSなんてのがあるのだ。これ見つけた時はコーヒー吹いたよあたしゃ）**

そんな、シェルスクリプトの互換性を気にしたいアナタにオススメな記事はこちら→。[どの環境でも使えるシェルスクリプトを書くためのメモ](http://qiita.com/richmikan@github/items/bd4b21cf1fe503ab2e5c)