Làm cách nào tôi có thể xử lý các bản ghi nhiều dòng với awk trong tập lệnh bash?


13

example.txt bên dưới

Restaurant: McDonalds 
City: Miami
State: Florida
Address: 123 Biscayne Blvd
Phone: 911

Restaurant: 5 guys
City: Atlanta
State: Georgia
Address: 123 Peachtree Rd
Phone: 911

Restaurant: KFC
City: NYC
State: NY
Address: 123 Madison Square
Phone: 911

Tôi đang sử dụng bash script và cho biết tôi muốn tìm kiếm một nhà hàng theo tên của nó từ tệp ở trên. Hỏi người dùng nhập tên nhà hàng và nó sẽ in thông tin liên quan đến nhà hàng đó (5 dòng).

awk '/McDonalds/> /KFC/' example.txt

Tôi biết rằng dòng mã ở trên sẽ in toàn bộ dòng phù hợp với mẫu "McDonalds" và "KFC" nhưng nó sẽ chỉ in dòng thứ 1 từ tệp văn bản chứ không phải phần còn lại của thông tin về nhà hàng đó. Làm cách nào tôi có thể yêu cầu nó in tất cả thông tin (5 dòng) chỉ từ đầu vào của người dùng tên nhà hàng?

Câu trả lời:


11

Với awk, bạn có thể thay đổi dấu tách bản ghi . Theo mặc định, nó là một dòng mới, vì vậy mỗi dòng của tệp là một bản ghi. Nếu bạn đặt RSbiến thành chuỗi trống, awk sẽ xem xét các bản ghi được phân tách bằng các dòng trống:

awk -v name="KFC" -v RS="" '$0 ~ "Restaurant: " name' example.txt

Tôi không hiểu câu hỏi của bạn. Nó khá mơ hồ. Đó có phải là sự phân công hay cách sử dụng mà bạn không nhận được?
glenn jackman

3

Sử dụng sed:

$ sed -n '/KFC/,/^$/p' file
Restaurant: KFC
City: NYC
State: NY
Address: 123 Madison Square
Phone: 911

$ sed -n '/McDo/,/^$/p' file
Restaurant: McDonalds
City: Miami
State: Florida
Address: 123 Biscayne Blvd
Phone: 911

Giải trình

Đây là sedchức năng cơ bản , bạn có thể tham khảo PHIẾU MỘT LẦN SỬ DỤNG CHO SED

# print section of file between two regular expressions (inclusive)
sed -n '/Iowa/,/Montana/p'             # case sensitive

Thêm lời giải thích.
BMW

Nhưng tại sao đề xuất chỉnh sửa bị từ chối? Tôi không thay đổi câu trả lời. Tôi vừa mới cải thiện định dạng.
cúc

2
$ awk '$2=="KFC" {print; for(i=1; i<=4; i++) { getline; print}}' example.txt

Restaurant: KFC
City: NYC
State: NY
Address: 123 Madison Square
Phone: 911

Lệnh trên sẽ nhận và in 4 dòng liên tiếp cùng với dòng hiện tại vì nó được đưa vào một vòng lặp for. Mẫu tìm kiếm $2=="KFC"sẽ giúp lấy một dòng cụ thể từ nhiều dòng.


0

Một giải pháp khả thi khác:

awk 'BEGIN{FS="\n";RS="\n\n"}{if($1=="KFC")print $0}' example.txt

{if($1=="KFC")print $0}thể được cô đọng lại $1 == "KFC", vì hành động mặc định cho một điều kiện thực là in bản ghi.
muru

0

Nó là đủ để in từ dòng chứa tên bạn muốn, đến dòng cuối cùng có chứa từ Phone(tất nhiên giả sử rằng tất cả các mục theo cùng một mẫu và sẽ luôn luôn có Phonebản ghi kết thúc)

$> awk '/5 guys/,/Phone/' restaurants.txt                                     
Restaurant: 5 guys
City: Atlanta
State: Georgia
Address: 123 Peachtree Rd
Phone: 911
$> awk '/McDonalds/,/Phone/' restaurants.txt                                  
Restaurant: McDonalds 
City: Miami
State: Florida
Address: 123 Biscayne Blvd
Phone: 911

Nếu chúng tôi muốn làm phức tạp nó một chút, chúng tôi có thể in chính xác 5 dòng sau trận đấu, như vậy:

awk '/McDonalds/{stop=NR+5}; NR<=stop ' restaurants.txt                    

Restaurant: McDonalds 
City: Miami
State: Florida
Address: 123 Biscayne Blvd
Phone: 911

Các stopbiến sẽ không được thiết lập, vì vậy NR<=stopsẽ không in bất cứ điều gì, cho đến khi /McDonalds/{stop=NR+5;}một phần thực sự thiết lập biến, và điều đó sẽ chỉ xảy ra khi chúng ta tìm thấy trận đấu.

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.