Como você remove o caractere de ponto da string sem chamar sed ou awk novamente?

12

Eu tenho um arquivo chamado hostlist.txt que contém texto como este:

host1.mydomain.com
host2.mydomain.com
anotherhost
www.mydomain.com
login.mydomain.com
somehost
host3.mydomain.com

Eu tenho o seguinte script pequeno:

#!/usr/local/bin/bash

while read host; do
        dig +search @ns1.mydomain.com $host ALL \
        | sed -n '/;; ANSWER SECTION:/{n;p;}';
done <hostlist.txt \
        | gawk '{print $1","$NF}' >fqdn-ip.csv

Quais são as saídas para fqdn-ip.csv :

host1.mydomain.com.,10.0.0.1
host2.mydomain.com.,10.0.0.2
anotherhost.internal.mydomain.com.,10.0.0.11
www.mydomain.com.,10.0.0.10
login.mydomain.com.,10.0.0.12
somehost.internal.mydomain.com.,10.0.0.13
host3.mydomain.com.,10.0.0.3

Minha pergunta é como remover o . antes da vírgula sem invocar sed ou gawk novamente? Existe uma etapa que posso executar nas chamadas sed ou gawk existentes que irão remover o ponto?

hostlist.txt conterá milhares de hosts, por isso quero que meu script seja rápido e eficiente.

    
por Linoob 26.05.2016 / 00:06

3 respostas

18

O comando sed , o comando awk e a remoção do período final podem ser combinados em um único comando awk:

while read -r host; do dig +search "$host" ALL; done <hostlist.txt | awk 'f{sub(/.$/,"",$1); print $1", "$NF; f=0} /ANSWER SECTION/{f=1}'

Ou, como se espalha em várias linhas:

while read -r host
do
    dig +search "$host" ALL
done <hostlist.txt | awk 'f{sub(/.$/,"",$1); print $1", "$NF; f=0} /ANSWER SECTION/{f=1}'

Como o comando awk segue a instrução done , apenas um awk process é chamado. Embora a eficiência possa não importar aqui, isso é mais eficiente do que criar um novo processo sed ou awk com cada loop.

Exemplo

Com este arquivo de teste:

$ cat hostlist.txt 
www.google.com
fd-fp3.wg1.b.yahoo.com

O comando produz:

$ while read -r host; do dig +search "$host" ALL; done <hostlist.txt | awk 'f{sub(/.$/,"",$1); print $1", "$NF; f=0} /ANSWER SECTION/{f=1}'
www.google.com, 216.58.193.196
fd-fp3.wg1.b.yahoo.com, 206.190.36.45

Como funciona

awk lê implicitamente sua entrada um registro (linha) de cada vez. Este script awk usa uma única variável, f , que indica se a linha anterior era um cabeçalho de seção de resposta ou não.

  • f{sub(/.$/,"",$1); print $1", "$NF; f=0}

    Se a linha anterior era um cabeçalho de seção de resposta, então f será true e os comandos em chaves serão executados. O primeiro remove o período final do primeiro campo. O segundo imprime o primeiro campo, seguido por , , seguido pelo último campo. A terceira instrução redefine f para zero (falso).

    Em outras palavras, f aqui funciona como uma condição lógica. Os comandos em chaves são executados se f for diferente de zero (que, em awk, significa 'true').

  • /ANSWER SECTION/{f=1}

    Se a linha atual contiver a string ANSWER SECTION , a variável f será definida como 1 (true).

    Aqui, /ANSWER SECTION/ serve como uma condição lógica. Ele é avaliado como verdadeiro se a corrente corresponder à expressão regular ANSWER SECTION . Em caso afirmativo, o comando em chaves é executado.

por 26.05.2016 / 00:31
7

dig pode ler em um arquivo que contém uma lista de nomes de host e processá-los um por um. Você também pode informar dig para suprimir todas as saídas, exceto a seção de respostas.

Isso deve fornecer a saída desejada:

dig -f hostlist.txt +noall +answer +search | 
    awk '{sub(/\.$/,"",$1); print $1","$5}'
A função awk do sub() é usada para remover o período literal . do final do primeiro campo. Então, awk imprime os campos 1 e 5 separados por uma vírgula.

NOTA: as entradas em hostlist.txt que não são resolvidas são completamente descartadas - elas não aparecem na stdout OR stderr.

(testado no Linux e no FreeBSD)

    
por 26.05.2016 / 07:03
6

Altere sua invocação de gawk para o seguinte:

| gawk '{print substr($1,1,length($1)-1)","$NF}' >fqdn-ip.csv
    
por 26.05.2016 / 00:32