Làm thế nào để bạn loại bỏ ký tự dấu chấm khỏi chuỗi mà không gọi lại sed hoặc awk?


12

Tôi có một tệp được gọi hostlist.txtcó chứa văn bản như thế này:

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

Tôi có đoạn script nhỏ sau:

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

Đầu ra nào 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

Câu hỏi của tôi là làm thế nào để tôi loại bỏ .ngay trước dấu phẩy mà không cần gọi lại sedhoặc gawkmột lần nữa? Có một bước tôi có thể thực hiện trong các cuộc gọi hiện có sedhoặc gawksẽ xóa dấu chấm?

hostlist.txt sẽ chứa 1000 máy chủ lưu trữ vì vậy tôi muốn kịch bản của mình nhanh và hiệu quả.


2
Bất kỳ lý do tại sao dig +shortkhông làm việc cho bạn?
Roger Lipscombe

@RogerLipscombe vì một số máy chủ lưu trữ trong hostlist.txt của tôi chỉ là tên máy chủ lưu trữ, không phải là FQDN nên tôi đang sử dụng + tìm kiếm để giải quyết chúng.
Linoob

Câu trả lời:


18

Tất sedcả các awklệnh, lệnh và loại bỏ dấu chấm đều có thể được kết hợp thành một lệnh awk duy nhất:

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

Hoặc, như trải ra trên nhiều dòng:

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

Bởi vì awklệnh tuân theo donecâu lệnh, chỉ có một awkquá trình được gọi. Mặc dù hiệu quả có thể không quan trọng ở đây, nhưng điều này hiệu quả hơn là tạo ra một quy trình sed hoặc awk mới với mỗi vòng lặp.

Thí dụ

Với tệp thử nghiệm này:

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

Lệnh tạo ra:

$ 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

Làm thế nào nó hoạt động

awk ngầm đọc một bản ghi (dòng) đầu vào của nó tại một thời điểm. Kịch bản awk này sử dụng một biến duy nhất, fbáo hiệu cho dù dòng trước đó có phải là tiêu đề của phần trả lời hay không.

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

    Nếu dòng trước là tiêu đề của phần trả lời, thì nó fsẽ đúng và các lệnh trong dấu ngoặc nhọn được thực thi. Cái đầu tiên loại bỏ khoảng thời gian từ trường đầu tiên. Trường thứ hai in trường đầu tiên, theo ,sau là trường cuối cùng. Câu lệnh thứ ba đặt lại fvề không (sai).

    Nói cách khác, fở đây có chức năng như một điều kiện logic. Các lệnh trong dấu ngoặc nhọn được thực thi nếu fkhông khác (trong awk, có nghĩa là 'true').

  • /ANSWER SECTION/{f=1}

    Nếu dòng hiện tại chứa chuỗi ANSWER SECTION, thì biến fđược đặt thành 1(true).

    Ở đây, /ANSWER SECTION/phục vụ như là một điều kiện hợp lý. Nó đánh giá là đúng nếu hiện tại khớp với biểu thức chính quy ANSWER SECTION. Nếu có, thì lệnh trong dấu ngoặc nhọn được thực thi.


Cảm ơn bạn @ John1024! Tôi không biết rằng awk không cần phải ở trong vòng lặp (tôi nghĩ rằng nó sẽ chỉ hoạt động ở dòng cuối cùng nếu nó ở bên ngoài). Là fmột biến tùy ý hoặc là f{}một phần rõ ràng của chức năng của awk?
Linoob

Chào mừng bạn flà một biến tùy ý. Bạn thực sự có thể đặt trước các {}điều kiện logic phức tạp. fchỉ là một điều kiện logic rất đơn giản: nó đúng nếu khác 0, sai nếu không.
John1024

@Linoob Lưu ý rằng trong lệnh thứ hai, /ANSWER SECTION/đóng vai trò điều kiện logic, tương tự như vai trò ftrong lệnh đầu tiên. Tôi đã cập nhật câu trả lời để thảo luận về điều này.
John1024

7

digcó thể đọc trong một tệp chứa danh sách tên máy chủ và xử lý từng cái một. Bạn cũng có thể yêu digcầu triệt tiêu tất cả đầu ra ngoại trừ phần trả lời.

Điều này sẽ cung cấp cho bạn đầu ra bạn muốn:

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

awk's sub()chức năng được sử dụng để lột giai đoạn đen .từ ngày kết thúc trường đầu tiên. Sau đó awkin các trường 1 và 5 cách nhau bằng dấu phẩy.

LƯU Ý: các mục trong hostlist.txtđó không giải quyết được loại bỏ hoàn toàn - chúng không xuất hiện trên thiết bị xuất chuẩn HOẶC thiết bị xuất chuẩn.

(Đã thử nghiệm trên Linux và FreeBSD)


6

Thay đổi lời mời của gawkbạn thành như sau:

| gawk '{print substr($1,1,length($1)-1)","$NF}' >fqdn-ip.csv
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.