¿Cómo se elimina el carácter de punto de la cadena sin volver a llamar a sed o awk?

12

Tengo un archivo llamado hostlist.txtque contiene texto como este:

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

Tengo el siguiente script pequeño:

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

Qué salidas 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

Mi pregunta es ¿cómo elimino el .justo antes de la coma sin invocar sedo de gawknuevo? ¿Hay algún paso que pueda realizar en las llamadas existentes sedo gawkque eliminen el punto?

hostlist.txt contendrá miles de hosts, por lo que quiero que mi script sea rápido y eficiente.

Linoob
fuente
2
¿Alguna razón por la dig +shortque no funciona para ti?
Roger Lipscombe
@RogerLipscombe porque algunos de los hosts en mi hostlist.txt son solo nombres de host, no FQDN, así que estoy usando + búsqueda para resolverlos.
Linoob

Respuestas:

18

El sedcomando, el awkcomando y la eliminación del período final se pueden combinar en un solo 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}'

O, como se extiende sobre varias líneas:

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

Debido a que el awkcomando sigue la donedeclaración, solo awkse invoca un proceso. Aunque la eficiencia puede no importar aquí, esto es más eficiente que crear un nuevo proceso sed o awk con cada ciclo.

Ejemplo

Con este archivo de prueba:

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

El 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

Cómo funciona

awk lee implícitamente su entrada un registro (línea) a la vez. Este script awk usa una sola variable, fque indica si la línea anterior era un encabezado de sección de respuesta o no.

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

    Si la línea anterior era un encabezado de sección de respuesta, fserá verdadera y se ejecutarán los comandos entre llaves. El primero elimina el período final del primer campo. El segundo imprime el primer campo, seguido de ,, seguido del último campo. La tercera declaración se restablece fa cero (falso).

    En otras palabras, faquí funciona como una condición lógica. Los comandos entre llaves se ejecutan si fno es cero (que, en awk, significa 'verdadero').

  • /ANSWER SECTION/{f=1}

    Si la línea actual contiene la cadena ANSWER SECTION, entonces la variable fse establece en 1(verdadero).

    Aquí, /ANSWER SECTION/sirve como una condición lógica. Se evalúa como verdadero si la corriente coincide con la expresión regular ANSWER SECTION. Si lo hace, entonces el comando entre llaves se ejecuta.

John1024
fuente
Gracias @ John1024! No sabía que awk no necesitaba estar dentro del circuito (pensé que solo actuaría en la última línea si estaba afuera). ¿Es funa variable arbitraria o es f{}una parte explícita de la funcionalidad de awk?
Linoob
De nada. fEs una variable arbitraria. En realidad, puede anteponer las {}complejas condiciones lógicas. fes una condición lógica muy simple: es verdadero si no es cero, falso si es cero.
John1024
@Linoob Tenga en cuenta que en el segundo comando, /ANSWER SECTION/desempeña el papel de condición lógica, análoga al papel fdesempeñado en el primer comando. He actualizado la respuesta para discutir esto.
John1024
7

digpuede leer en un archivo que contiene una lista de nombres de host y procesarlos uno por uno. También puede indicar digque suprima todos los resultados, excepto la sección de respuesta.

Esto debería darle la salida que desea:

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

awkLa sub()función de se utiliza para eliminar el período literal .desde el final del primer campo. Luego awkimprime los campos 1 y 5 separados por una coma.

NOTA: las entradas hostlist.txtque no se resuelven se descartan por completo; no aparecen en stdout O stderr.

(Probado en Linux y FreeBSD)

cas
fuente
6

Cambie su invocación de gawka lo siguiente:

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