Як видалити символ крапки з рядка, не викликаючи знову або awk?


12

У мене називається файл, hostlist.txtякий містить такий текст:

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

У мене є такий маленький сценарій:

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

Які виходи 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

Моє запитання - як я можу видалити .безпосередньо перед комою без виклику sedчи gawkзнову? Чи є крок, який я можу виконати в існуючих sedабо gawkдзвінках, які знімуть крапку?

hostlist.txt міститиме 1000 тисяч хостів, тому я хочу, щоб мій сценарій був швидким та ефективним.


2
Будь-яка причина, чому dig +shortдля вас не працює?
Роджер Ліпскомб

@RogerLipscombe, оскільки деякі хости в моєму списку хостів.txt - це просто імена хостів, а не FQDN, тому я використовую + пошук для їх вирішення.
Linoob

Відповіді:


18

sedКоманди, то awkкоманда, і видалення заднього періоду все вони можуть бути об'єднані в одну команду 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}'

Або, як розподілено по декількох рядках:

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

Оскільки awkкоманда слідує за doneтвердженням, awkвикликається лише один процес. Хоча ефективність тут може не мати значення, це є більш ефективним, ніж створення нового процесу sed або awk з кожним циклом.

Приклад

За допомогою цього тестового файлу:

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

Команда виробляє:

$ 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

Як це працює

awk неявно читає вхід по одному запису (рядку) за один раз. Цей скрипт awk використовує єдину змінну, fяка сигналізує, чи був попередній рядок заголовком розділу відповідей чи ні.

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

    Якщо попередній рядок був заголовком розділу відповідей, тоді fбуде істинним, і команди в фігурних дужках виконуються. Перше видаляє проміжок часу з першого поля. Друге друкує перше поле, за ним ,слідує, а потім - останнє. Третє твердження скидає fдо нуля (false).

    Іншими словами, fтут функціонує як логічна умова. Команди в фігурних дужках виконуються, якщо fце ненульове значення (що, власне, означає «істина»).

  • /ANSWER SECTION/{f=1}

    Якщо поточний рядок містить рядок ANSWER SECTION, то для змінної fвстановлено значення 1(true).

    Тут /ANSWER SECTION/виступає логічною умовою. Він оцінюється як істинне, якщо поточний відповідає регулярному виразу ANSWER SECTION. Якщо так, то команда в фігурних дужках виконується.


Дякую @ John1024! Я не знав, що awk не повинен бути в циклі (я думав, що він буде діяти лише на останньому рядку, якщо він буде зовні). Це fдовільна змінна чи f{}явна частина функціоналу awk?
Linoob

Прошу. fє довільною змінною. Ви можете реально поставити перед {}складними логічними умовами. fце просто дуже проста логічна умова: це правда, якщо нуль, помилково, якщо нуль.
John1024

@Linoob Зауважимо, що у другій команді /ANSWER SECTION/відіграє роль логічного стану, аналогічного ролі, яку fвідіграє перша команда. Я оновив відповідь, щоб обговорити це.
John1024

7

digможе читати у файлі, що містить список імен хостів, і обробляти їх по одному. Ви також можете сказати digпридушити всі результати, крім розділу відповідей.

Це має дати вам потрібний вихід:

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

awksub()Функція 's використовується для зняття буквального періоду .з кінця першого поля. Потім awkдрукуються поля 1 і 5, розділені комою.

ПРИМІТКА: записи hostlist.txt, які не вирішуються, повністю відкидаються - вони не відображаються на stdout АБО stderr.

(Тестовано на Linux та FreeBSD)


6

Змініть виклик gawkна таке:

| gawk '{print substr($1,1,length($1)-1)","$NF}' >fqdn-ip.csv
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.