Jak usunąć znak kropki z łańcucha bez ponownego wywoływania sed lub awk?


12

Mam plik o nazwie, hostlist.txtktóry zawiera taki tekst:

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

Mam następujący mały skrypt:

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

Które wyniki 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

Moje pytanie brzmi: jak usunąć .tuż przed przecinkiem bez wywoływania sedlub gawkponownie? Czy istnieje krok, który mogę wykonać w ramach istniejących połączeń sedlub gawkpołączeń, które usuną kropkę?

hostlist.txt będzie zawierać tysiące hostów, więc chcę, aby mój skrypt był szybki i wydajny.


2
Jest jakiś powód, dla którego dig +shortnie działa dla Ciebie?
Roger Lipscombe

@RogerLipscombe, ponieważ niektóre hosty z mojej listy hostlist.txt to tylko nazwy hostów, a nie nazwy FQDN, więc używam + + do ich rozwiązania.
Linoob

Odpowiedzi:


18

sedPolecenia, awkpolecenia i usunięcie kropki mogą być wszystkie połączone w jednym poleceniu 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}'

Lub, jak rozłożone na wiele linii:

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

Ponieważ awkpolecenie występuje po doneinstrukcji, awkwywoływany jest tylko jeden proces. Chociaż wydajność może tutaj nie mieć znaczenia, jest to bardziej wydajne niż tworzenie nowego procesu sed lub awk przy każdej pętli.

Przykład

Za pomocą tego pliku testowego:

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

Polecenie powoduje:

$ 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

Jak to działa

awk domyślnie odczytuje swoje wejście po jednym rekordzie (linii) na raz. Ten skrypt awk używa jednej zmiennej, fktóra sygnalizuje, czy poprzedni wiersz był nagłówkiem sekcji odpowiedzi, czy nie.

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

    Jeśli poprzedni wiersz był nagłówkiem sekcji odpowiedzi, wówczas fbędzie to prawda, a polecenia w nawiasach klamrowych zostaną wykonane. Pierwszy usuwa kropkę z pierwszego pola. Drugi drukuje pierwsze pole, a następnie ,, a następnie ostatnie pole. Trzecia instrukcja resetuje się fdo zera (fałsz).

    Innymi słowy, ftutaj funkcjonuje jako warunek logiczny. Polecenia w nawiasach klamrowych są wykonywane, jeśli fjest niezerowe (co w awk oznacza „prawda”).

  • /ANSWER SECTION/{f=1}

    Jeśli bieżący wiersz zawiera ciąg ANSWER SECTION, zmienna fjest ustawiona na 1(prawda).

    Tutaj /ANSWER SECTION/służy jako warunek logiczny. Sprawdza, czy bieżący pasuje do wyrażenia regularnego ANSWER SECTION. Jeśli tak, to polecenie w nawiasach klamrowych jest wykonywane.


Dziękuję @ John1024! Nie wiedziałem, że awk nie musi znajdować się w pętli (myślałem, że zadziała tylko na ostatniej linii, jeśli będzie na zewnątrz). Czy fdowolna zmienna lub jest f{}wyraźną częścią funkcjonalności awk?
Linoob

Proszę bardzo. fjest dowolną zmienną. Możesz postawić przed {}złożonymi warunkami logicznymi. fjest tylko bardzo prostym warunkiem logicznym: to prawda, jeśli niezerowa, fałsz, jeśli zero.
John1024

@Linoob Zauważ, że w drugim poleceniu /ANSWER SECTION/pełni rolę warunku logicznego, analogicznie do roli fodgrywanej w pierwszym poleceniu. Zaktualizowałem odpowiedź, aby to omówić.
John1024

7

digumie czytać w pliku zawierającym listę nazw hostów i przetwarzać je jeden po drugim. Możesz także powiedzieć, digaby ukryć wszystkie dane wyjściowe oprócz sekcji odpowiedzi.

To powinno dać ci pożądany wynik:

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

awk„s sub()funkcja służy do taśmy dosłownego okres .od końca pierwszego pola. Następnie awkdrukuje pola 1 i 5 oddzielone przecinkiem.

UWAGA: wpisy hostlist.txtnierozstrzygnięte są całkowicie odrzucane - nie pojawiają się na stdout LUB stderr.

(Testowany na Linuksie i FreeBSD)


6

Zmień swoje wywołanie gawkna:

| gawk '{print substr($1,1,length($1)-1)","$NF}' >fqdn-ip.csv
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.