web-dev-qa-db-ja.com

bashコマンドの出力をキャプチャして解析し、さまざまなbash変数に保存します

説明:

小さなbashスクリプトがあり、anyLinuxコマンドを実行するだけです(例:ifconfig

ifconfigの一般的な出力は次のようになります。

eth0      Link encap:Ethernet  HWaddr 30:F7:0D:6D:34:CA
          inet addr:10.106.145.12  Bcast:10.106.145.255  Mask:255.255.255.0
          inet6 addr: fe80::32f7:dff:fe6d:34ca/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1104666 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2171 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:444437904 (423.8 MiB)  TX bytes:238380 (232.7 KiB)

lo        Link encap:Local Loopback 
          inet addr:127.0.0.1  Mask:255.255.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:15900 errors:0 dropped:0 overruns:0 frame:0
          TX packets:15900 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:467306 (456.3 KiB)  TX bytes:467306 (456.3 KiB)

これで、ほとんどの人は通常、entire出力をファイル/変数に格納し、それに基づいて解析します。しかし、とにかく出力の固有の部分を複数の変数(たとえばbash変数${IPETH0}を呼び出してIPアドレス10.106.145.12eth0から送信し、${IPLO}を呼び出してIPアドレス127.0.0.1lo上記の例ではifconfigコマンドを2回実行せずに)。

teeコマンドが入力に対して行うことのようなものですが、outputに対してこれを実行して、出力を2またはmore変数を一度に。何か案は?

6
Arpith

答えを得ました:

$ read IPETH0 IPLO <<< $(ifconfig | awk '/inet[[:space:]]/ { print $2 }' | cut -d ':' -f 2)
$ echo "${IPETH0}"
192.168.23.2
$ echo "${IPLO}"
127.0.0.1

これは、eth0およびloインターフェースの順序を想定していますが、基本的な考え方を示しています。

純粋awk

これは、awk関数を使用してsplitで排他的に実行できます。

$ read IPETH0 IPLO <<< $(ifconfig | awk '/inet[[:space:]]/ { split($2,a,":"); print a[2]}')
5
Arpith

コマンドのリターンのどの部分を保存したいか、コマンドごとに知っていると思います。

あなたの例では、これは単語番号7と47になります。

次のようにします(コマンドifconfigの前後のティックに注意してください)。

array=(`ifconfig`)

この配列のすべての要素を表示:

echo ${array[@]}
eth0 Link encap:Ethernet HWaddr 30:F7:0D:6D:34:CA inet addr:10.106.145.12 Bcast:10.106.145.255 Mask:255.255.255.0 inet6 addr: fe80::32f7:dff:fe6d:34ca/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1104666 errors:0 dropped:0 overruns:0 frame:0 TX packets:2171 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:444437904 (423.8 MiB) TX bytes:238380 (232.7 KiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.255.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:15900 errors:0 dropped:0 overruns:0 frame:0 TX packets:15900 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:467306 (456.3 KiB) TX bytes:467306 (456.3 KiB)

特定の単語を表示:

echo ${array[6]} ${array[46]}
addr:10.106.145.12 addr:127.0.0.1

結果をsedにパイプして、IPアドレスのみを抽出します。

echo ${array[6]} ${array[46]} | sed 's/addr://g'
10.106.145.12 127.0.0.1

ここで「読み取り」を使用してArpithの気の利いたアプローチを使用すると、柔軟な答えになります。

read IPETH0 IPLO <<< $(echo ${array[6]} ${array[46]} |\
sed 's/addr://g')
echo $IPETH0 $IPLO
10.106.145.12 127.0.0.1

配列要素は0から数えられることに注意してください。したがって、Word番号7は「$ {array [6]}」と呼ばれます。

配列のインデックスは正の整数です。したがって、シェルスクリプトであらゆる種類の計算を実行して、特定の単語(範囲やforループなど)を選択できます...

移植可能なスクリプトを作成するには、これらの数値を含む一種のテーブルを保持する必要があります。私のシステム(BSD)では、IPアドレスはLinuxの番号7と47ではなく、番号17と49になります。また、結果の文字列は異なって見えます(ローカルとArpithのグローバルIDアドレスに関係なく):

echo ${array2[16]}
192.168.0.103

echo ${array2[48]}
127.0.0.1

slmの「純粋なawk」アプローチ(下記参照)は、私のBSDシステムでは失敗します。 「ifconfig」コマンドが「127.0.0.1」とArpithの「addr:127.0.0.1」を出力するため、配列への関数の分割は機能しません...

read IPETH0 IPLO <<< $(ifconfig |\
 awk '/inet[[:space:]]/ { split($2,a,":"); print a[2]}')

HTH

バーニー

2
Bernie Reiter

これを行う通常の方法は、たとえばawkbashコードを生成させ、それをbashで解釈させることです。

お気に入り:

eval "$(
  ifconfig | awk -F '[: ]+' '
    /^[^[:blank:]]/ {iface=$1}
    /inet addr:/ {ip[iface]=$4}
    END {for (i in ip) print "IP" toupper(i) "=" ip[i]}')"
1

[〜#〜] awk [〜#〜]

/sbin/ifconfig | awk -F':' 'NR==2{split($2,a," "); print a[1]}'

[〜#〜] sed [〜#〜]

ip -f inet addr show dev eth0 | sed -n 's/^ *inet *\([.0-9]*\).*/\1/p'

OR

ifconfig eth0 | sed -n 's/^ *inet addr:*\([.0-9]*\).*/\1/p'

[〜#〜] grep [〜#〜]

ifconfig eth0|grep -Po 't addr:\K[\d.]+'

@Stephane Chazelasに感謝

1
Rahul Patil