Wie entfernt man ein Punktzeichen aus einer Zeichenkette, ohne erneut sed oder awk aufzurufen?

12

Ich habe eine Datei mit dem Namen hostlist.txt, die folgenden Text enthält:

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

Ich habe das folgende kleine Skript:

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

Welche Ausgänge zu 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

Meine Frage ist, wie entferne ich .das Komma kurz vor, ohne es aufzurufen sedoder gawkerneut? Gibt es einen Schritt, den ich in den vorhandenen ausführen kann, sedoder gawkAnrufe, die den Punkt entfernen?

hostlist.txt Ich möchte, dass mein Skript schnell und effizient ist.

Linoob
quelle
2
Irgendein Grund, warum dig +shortes bei Ihnen nicht funktioniert?
Roger Lipscombe
@ RogerLipscombe, da einige der Hosts in meiner hostlist.txt nur Hostnamen und keine vollqualifizierten Domänennamen sind.
Linoob

Antworten:

18

Der sedBefehl, der awkBefehl und das Entfernen der Nachlaufzeit können zu einem einzigen awk-Befehl zusammengefasst werden:

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

Oder über mehrere Zeilen verteilt:

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

Da der awkBefehl der Anweisung folgt done, wird nur ein awkProzess aufgerufen. Obwohl Effizienz hier keine Rolle spielt, ist dies effizienter, als mit jeder Schleife einen neuen Sed- oder Awk-Prozess zu erstellen.

Beispiel

Mit dieser Testdatei:

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

Der Befehl erzeugt:

$ 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

Wie es funktioniert

awk liest implizit seine Eingabe einen Datensatz (Zeile) nach dem anderen. Dieses awk-Skript verwendet eine einzelne Variable, fdie angibt, ob die vorherige Zeile ein Antwortabschnitt-Header war oder nicht.

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

    Wenn die vorherige Zeile eine Kopfzeile des Antwortabschnitts war, ist fsie true und die Befehle in geschweiften Klammern werden ausgeführt. Die erste entfernt die abschließende Periode aus dem ersten Feld. Der zweite druckt das erste Feld ,, gefolgt von dem letzten Feld. Die dritte Anweisung wird fauf Null zurückgesetzt (falsch).

    Mit anderen Worten fungiert fhier als logische Bedingung. Die Befehle in geschweiften Klammern werden ausgeführt, wenn sie fungleich Null sind (was in awk 'wahr' bedeutet).

  • /ANSWER SECTION/{f=1}

    Wenn die aktuelle Zeile den String enthält ANSWER SECTION, wird die Variable fauf 1(true) gesetzt.

    Hier /ANSWER SECTION/dient als logische Bedingung. Es wird als wahr ausgewertet, wenn der Strom mit dem regulären Ausdruck übereinstimmt ANSWER SECTION. Wenn dies der Fall ist, wird der Befehl in geschweiften Klammern ausgeführt.

John1024
quelle
Vielen Dank @ John1024! Ich wusste nicht, dass awk nicht in der Schleife sein musste (ich dachte, dass es nur in der letzten Zeile wirken würde, wenn es draußen wäre). Ist feine beliebige Variable oder f{}ein expliziter Teil der Funktionalität von awk?
Linoob
Gern geschehen. fist eine beliebige Variable. Sie können die {}komplexen logischen Bedingungen tatsächlich vorgeben. fist nur eine sehr einfache logische Bedingung: Es ist wahr, wenn nicht Null, falsch, wenn Null.
John1024
@Linoob Beachten Sie, dass im zweiten Befehl /ANSWER SECTION/analog zur Rolle fim ersten Befehl die Rolle der logischen Bedingung gespielt wird. Ich habe die Antwort aktualisiert, um dies zu diskutieren.
John1024
7

digkann eine Datei mit einer Liste von Hostnamen einlesen und einzeln verarbeiten. Sie können auch festlegen dig, dass alle Ausgaben mit Ausnahme des Antwortbereichs unterdrückt werden sollen.

Dies sollte Ihnen die Ausgabe geben, die Sie wollen:

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

awkMit der sub()Funktion von wird die Literalperiode .vom Ende des ersten Feldes entfernt. Dann werden awkdie durch Komma getrennten Felder 1 und 5 gedruckt.

HINWEIS: Einträge hostlist.txt, die nicht aufgelöst werden, werden vollständig verworfen - sie werden nicht in stdout ODER stderr angezeigt.

(Getestet unter Linux und FreeBSD)

cas
quelle
6

Ändern Sie Ihren Aufruf gawkwie folgt:

| gawk '{print substr($1,1,length($1)-1)","$NF}' >fqdn-ip.csv
DopeGhoti
quelle