Bagaimana Anda menghapus karakter titik dari string tanpa memanggil sed atau awk lagi?

12

Saya memiliki file bernama hostlist.txtyang berisi teks seperti ini:

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

Saya memiliki skrip kecil berikut:

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

Yang menghasilkan 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

Pertanyaan saya adalah bagaimana cara menghapus .sebelum koma tanpa meminta sedatau gawklagi? Apakah ada langkah yang bisa saya lakukan dalam panggilan yang ada sedatau gawkyang akan menghapus titik?

hostlist.txt akan berisi 1000-an host jadi saya ingin skrip saya menjadi cepat dan efisien.

Linoob
sumber
2
Ada alasan mengapa dig +shorttidak berhasil untuk Anda?
Roger Lipscombe
@RogerLipscombe karena beberapa host di hostlist.txt saya hanya nama host, bukan FQDN jadi saya menggunakan pencarian + untuk menyelesaikannya.
Linoob

Jawaban:

18

The sedperintah, awkperintah, dan penghapusan periode mengikuti semua dapat digabungkan ke dalam perintah awk tunggal:

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

Atau, seperti tersebar di beberapa baris:

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

Karena awkperintah mengikuti donepernyataan, hanya satu awkproses yang dipanggil. Meskipun efisiensi mungkin tidak penting di sini, ini lebih efisien daripada menciptakan proses sed atau awk baru dengan setiap loop.

Contoh

Dengan file tes ini:

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

Perintah menghasilkan:

$ 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

Bagaimana itu bekerja

awk secara implisit membaca inputnya satu rekaman (baris) pada suatu waktu. Script awk ini menggunakan variabel tunggal f,, yang menandakan apakah baris sebelumnya adalah header bagian jawaban atau tidak.

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

    Jika baris sebelumnya adalah tajuk bagian jawaban, maka fakan benar dan perintah di kurung kurawal dieksekusi. Yang pertama menghapus periode trailing dari bidang pertama. Yang kedua mencetak bidang pertama, diikuti oleh ,, diikuti oleh bidang terakhir. Pernyataan ketiga diatur ulang fke nol (salah).

    Dengan kata lain, di fsini berfungsi sebagai kondisi logis. Perintah dalam kurung kurawal dieksekusi jika fbukan nol (yang, dalam awk, berarti 'benar').

  • /ANSWER SECTION/{f=1}

    Jika baris saat ini berisi string ANSWER SECTION, maka variabel fdiatur ke 1(true).

    Di sini, /ANSWER SECTION/berfungsi sebagai kondisi logis. Ini bernilai true jika saat ini cocok dengan ekspresi reguler ANSWER SECTION. Jika ya, maka perintah di kurung kurawal di jalankan.

John1024
sumber
Terima kasih @ John1024! Saya tidak tahu bahwa awk tidak perlu berada di dalam loop (saya pikir itu hanya akan bertindak pada baris terakhir jika ada di luar). Apakah fvariabel arbitrer atau merupakan f{}bagian eksplisit dari fungsi awk?
Linoob
Sama-sama. fadalah variabel arbitrer. Anda benar-benar dapat menempatkan sebelum {}kondisi logis yang kompleks. fhanyalah kondisi logis yang sangat sederhana: memang benar jika bukan nol, salah jika nol.
John1024
@Linoob Perhatikan bahwa dalam perintah kedua, /ANSWER SECTION/memainkan peran kondisi logis, analog dengan peran yang fdimainkan di perintah pertama. Saya telah memperbarui jawaban untuk membahas ini.
John1024
7

digdapat membaca dalam file yang berisi daftar nama host dan memprosesnya satu per satu. Anda juga dapat meminta diguntuk menekan semua output kecuali bagian jawaban.

Ini akan memberi Anda output yang Anda inginkan:

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

awk's sub()Fungsi ini digunakan untuk mengupas periode literal .dari akhir field pertama. Kemudian awkmencetak bidang 1 dan 5 dipisahkan dengan koma.

CATATAN: entri hostlist.txtyang tidak diselesaikan sepenuhnya dibuang - entri yang tidak muncul di stdout ATAU stderr.

(Diuji di Linux dan FreeBSD)

cas
sumber
6

Ubah permintaan Anda gawkmenjadi sebagai berikut:

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