Come si rimuove il carattere punto dalla stringa senza chiamare di nuovo sed o awk?


12

Ho un file chiamato hostlist.txtche contiene testo come questo:

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

Ho il seguente piccolo script:

#!/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

Che produce a 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

La mia domanda è: come posso rimuovere il .poco prima della virgola senza richiamare sedo di gawknuovo? Esiste un passaggio che posso eseguire nell'esistente sedo nelle gawkchiamate che rimuoveranno il punto?

hostlist.txt conterrà migliaia di host, quindi voglio che il mio script sia veloce ed efficiente.


2
Qualche motivo per cui dig +shortnon funziona per te?
Roger Lipscombe,

@RogerLipscombe perché alcuni host nel mio hostlist.txt sono solo nomi host, non nomi di dominio completi, quindi sto usando + ricerca per risolverli.
Linoob,

Risposte:


18

Il sedcomando, il awkcomando e la rimozione del periodo finale possono essere combinati in un unico 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}'

Oppure, come distribuito su più righe:

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}'

Poiché il awkcomando segue l' doneistruzione, awkviene richiamato un solo processo. Anche se l'efficienza può non avere importanza qui, è più efficiente della creazione di un nuovo processo sed o awk con ogni ciclo.

Esempio

Con questo file di prova:

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

Il comando produce:

$ 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

Come funziona

awk legge implicitamente il suo input un record (riga) alla volta. Questo script awk utilizza una singola variabile, fche indica se la riga precedente era un'intestazione della sezione di risposta o meno.

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

    Se la riga precedente era un'intestazione della sezione di risposta, allora fsarà vera e verranno eseguiti i comandi tra parentesi graffe. Il primo rimuove il periodo finale dal primo campo. Il secondo stampa il primo campo, seguito da ,, seguito dall'ultimo campo. La terza istruzione viene reimpostata fsu zero (false).

    In altre parole, fqui funziona come una condizione logica. I comandi tra parentesi graffe vengono eseguiti se fè diverso da zero (che, in awk, significa "vero").

  • /ANSWER SECTION/{f=1}

    Se la riga corrente contiene la stringa ANSWER SECTION, la variabile fè impostata su 1(true).

    Qui, /ANSWER SECTION/serve come condizione logica. Valuta vero se la corrente corrisponde all'espressione regolare ANSWER SECTION. In tal caso, il comando tra parentesi graffe viene eseguito.


Grazie @ John1024! Non sapevo che awk non avesse bisogno di essere all'interno del loop (pensavo che avrebbe agito sull'ultima riga solo se fosse fuori). È funa variabile arbitraria o è f{}una parte esplicita della funzionalità di awk?
Linoob,

Prego. fè una variabile arbitraria. Puoi effettivamente mettere le {}condizioni logiche complesse. fè solo una condizione logica molto semplice: è vero se diverso da zero, falso se zero.
Giovanni 1024,

@Linoob Si noti che nel secondo comando, /ANSWER SECTION/svolge il ruolo di condizione logica, analogo al ruolo fsvolto nel primo comando. Ho aggiornato la risposta per discuterne.
Giovanni 1024,

7

digpuò leggere in un file contenente un elenco di nomi host ed elaborarli uno per uno. Puoi anche dire digdi sopprimere tutti gli output tranne la sezione delle risposte.

Questo dovrebbe darti l'output che desideri:

dig -f hostlist.txt +noall +answer +search | 
    awk '{sub(/\.$/,"",$1); print $1","$5}'

awkLa sub()funzione viene utilizzata per eliminare il periodo letterale .dalla fine del primo campo. Quindi awkstampa i campi 1 e 5 separati da una virgola.

NOTA: le voci hostlist.txtche non vengono risolte vengono completamente eliminate - non vengono visualizzate su stdout O su stderr.

(Testato su Linux e FreeBSD)


6

Cambia la tua invocazione gawkcome segue:

| gawk '{print substr($1,1,length($1)-1)","$NF}' >fqdn-ip.csv
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.