Script para fazer referência a outro arquivo primeiro

2

Oi eu tenho um script e nele eu preciso obter os nomes de host de IPs que o script gera. O script irá gerar esses IPs em 1 arquivo puro com apenas 1 coluna. É literalmente apenas o endereço IP (1 para cada linha). Eu tenho outro arquivo chamado 'db' que se parece com isso:

IP Hostname

'db' é meu banco de dados que armazena uma lista de endereços IP e nomes de host que são delegados a esses IPs. Estes são endereço estático e não serão alterados, geralmente servidores ou switches, etc. O que eu preciso é para os endereços IP que o script gera, eu gostaria de resolvê-los com os nomes de host em PRIMEIRO lugar a partir deste arquivo de banco de dados e se isso não acontecer encontre-o lá e execute o comando host . Eu já estou fazendo o último com host , mas eu realmente quero que eles vêm do meu arquivo db primeiro. A saída final precisa ser apenas 1 arquivo com 1 coluna de nomes de host. Eu tenho algumas idéias usando o awk com arrays, mas não consigo obter exatamente o que preciso.

    
por unixpipe 19.09.2014 / 01:27

1 resposta

6

grep é o comando cujo objetivo principal é procurar texto por um padrão (ou padrões). Sua aplicação simplista para esta tarefa seria

grep 1.2.3.4 db

que produzirá a (s) linha (s) " IP_address Hostname " do arquivo db que correspondem ao padrão “ 1.2.3.4 ”. Note que eu disse linha (s) (ao invés de linha ) e combina o padrão (em vez de conter a string ), porque há algumas dicas aqui.

  • Uma é que grep , como eu já disse, (por padrão) procura por padrões ao invés de strings . Esses padrões são chamados de expressões regulares e há um mundo de documentação sobre eles. O fato mais importante sobre regexs para esta discussão é que um período, " . ", é um padrão que corresponde a qualquer caractere único. Então, por exemplo, o padrão ( regex ) 1.2.3.4 corresponderia às strings 132.364 e 1a2b3c4 . Estes provavelmente não são um problema no que diz respeito à coluna IP_address , mas essas sequências podem aparecer na coluna Hostname .
  • Outra é que, a menos que especificado de outra forma, grep procura o padrão fornecido em qualquer lugar na linha . Assim, o padrão 1.2.3.4 corresponderia a linhas contendo 31.2.3.4 e 1.2.3.42 .

Mas acredito que você fará um bom trabalho ao conseguir a linha que deseja - e apenas essa linha - com o comando

grep "^1.2.3.4[[:space:]]" db

onde

  • ^ ” é outro caractere especial em expressões regulares; isso significa que esse padrão deve aparecer no início de uma linha.
  • [[:space:]] ” representa um caractere de espaço em branco; um espaço ou uma tabulação. Se você tiver certeza de que seu arquivo db usa apenas espaços, basta procurar um espaço; por exemplo,

    grep "^1.2.3.4 " db
    

Eles ainda encontrarão linhas que começam com 132.364 ou 1a2b3c4 . Mas, se o seu arquivo db estiver estruturado corretamente, você não deve ter essas strings no início das linhas no seu arquivo db .

Você pode impedir que " . " corresponda a caracteres arbitrários com qualquer um dos seguintes itens:

  • grep "^1\.2\.3\.4[[:space:]]" db
  • grep "^1\.2\.3\.4 " db
  • grep -F "1.2.3.4 " db

mas os dois primeiros exigirão que você salte pelos aros do seu script para converter 1.2.3.4 para 1\.2\.3\.4 , e o terceiro elimina o significado especial de " ^ " (então 31.2.3.4 ainda corresponderá).

Como dito acima, todos esses comandos correspondem a toda a linha do arquivo db que corresponde ao endereço IP. Para obter apenas o nome do host (a segunda coluna), use

grep "^1.2.3.4[[:space:]]" db | awk '{print $2}'

Isso apenas escreverá o nome do host na saída padrão (normalmente, a tela). Uma operação mais útil em um script seria

db_host=$(grep "^1.2.3.4[[:space:]]" db | awk '{print $2}')

que captura essa saída na variável do shell db_host .

Então, finalmente, esta seção do seu script pode parecer algo como

db_host=$(grep "^$this_IP_address[[:space:]]" db | awk '{print $2}')
if [ "$db_host" = "" ]
then
    Use the host command.
          ︙
fi

que você colocaria em um loop, em que a variável this_IP_address aceita cada endereço IP que você deseja processar. Se você os tiver em um arquivo (ou seja, outro arquivo, separado de db ), então leia esse arquivo uma linha de cada vez.

Por exemplo, se você tiver endereços IP (um por linha) em um arquivo chamado src_ip , e tudo que você quer fazer é escrever os nomes de host para a saída padrão, você poderia dizer,

while read this_IP_address
do
    db_host=$(grep "^$this_IP_address[[:space:]]" db | awk '{print $2}')
    if [ "$db_host" = "" ]
    then
        # Use the host command to lookup $this_IP_address.
        host "$this_IP_address" | head -n 1 | awk '{print $5}'
    else
        echo "$db_host"
    fi
done < src_ip

grep -f src_ip db não seria particularmente útil para o problema que você está descrevendo (se eu entendi corretamente) porque iria denunciar todas as linhas em db que correspondem a qualquer endereço IP em src_ip - deixando você descobrir quais endereços IP não foram correspondidos.

Uma maneira mais simples de fazer isso me ocorreu:

awk -v this_one="$this_IP_address" '$1 == this_one {print $2}' db

que copia a variável do shell this_IP_address para awk variable this_one e depois diz "imprima o segundo campo de qualquer linha cujo primeiro campo seja igual a this_one ". Este é um processo, ao contrário de dois, e elimina o problema de " . " caracteres arbitrários correspondentes. Envolva-o em db_host=$(…) como antes.

    
por 19.09.2014 / 03:43