Captura a saída de um comando bash, analisa-o e armazena em diferentes variáveis bash

6

Explicação:

Eu tenho um pequeno script bash que simplesmente executa qualquer comando Linux (por exemplo, digamos ifconfig )

A saída típica de ifconfig é algo assim:

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)

Agora, o que a maioria das pessoas costuma fazer é armazenar a saída inteira em um arquivo / variável e analisar com base nisso. No entanto, quero saber se há algo em que eu poderia colocar partes específicas da saída em mais de uma variável (digamos uma variável bash chamada ${IPETH0} para carregar o IP enderece 10.106.145.12 de eth0 e ${IPLO} para carregar o endereço IP 127.0.0.1 de lo no exemplo acima sem executar o comando ifconfig duas vezes ).

Algo parecido com o comando tee faz com a entrada, mas eu quero fazer isso para a saída e armazenar a saída em 2 ou mais variáveis de uma só vez. Alguma idéia?

    
por Arpith 26.08.2013 / 20:18

4 respostas

5

Tenho a resposta:

$ 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

Isso pressupõe a ordem das interfaces eth0 e lo , mas mostra a ideia básica.

Puro awk

Você pode fazer isso exclusivamente em awk usando a função split :

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

Eu presumo que você saiba para cada um dos seus comandos qual parte do retorno do comando você quer armazenar.

No seu exemplo, seriam as palavras 7 e 47.

Faça assim (note a volta do seu comando ifconfig ):

array=('ifconfig')

Mostrar todos os elementos desta matriz:

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)

Mostrar palavras específicas:

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

canalize o resultado para o sed para extrair apenas os seus endereços IP:

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

Usar a abordagem bacana de Arpith com 'read' aqui é a resposta flexível.

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

Por favor, note que os elementos da matriz estão sendo contados a partir de 0. Portanto, o número da sua palavra 7 seria referido como "$ {array [6]}".

Os índices da matriz são inteiros positivos. Assim, você pode fazer todos os tipos de cálculos em seu script de shell para escolher palavras específicas (como intervalos ou para-loops) ...

Para escrever um script portátil, você precisaria manter um tipo de tabela com esses números. No meu sistema (BSD), os endereços IP seriam os números 17 e 49, em vez dos números 7 e 47 do Linux. Também as sequências resultantes são diferentes (desconsiderando o endereço de ID global do local e da Arpith):

echo ${array2[16]}
192.168.0.103

echo ${array2[48]}
127.0.0.1
A abordagem "pure awk" do

slm (veja abaixo) falharia no meu sistema BSD. A função split em um array não funcionaria como o meu comando 'ifconfig' imprime "127.0.0.1" e "addr: 127.0.0.1" do Arpith ...

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

HTH

bernie

    
por 26.08.2013 / 21:02
1

Uma maneira comum de fazer isso é ter, por exemplo, awk gerar algum bash code e interpretá-lo por bash .

Como:

eval "$(
  ifconfig | awk -F '[: ]+' '
    /^[^[:blank:]]/ {iface=$1}
    /inet addr:/ {ip[iface]=$4}
    END {for (i in ip) print "IP" toupper(i) "=" ip[i]}')"
    
por 26.08.2013 / 21:41
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]*\).*//p'

OR

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

GREP :

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

Obrigado ao @Stephane Chazelas

    
por 26.08.2013 / 22:32