Sử dụng nhiều dấu phân cách trong awk


202

Tôi có một tập tin chứa các dòng sau:

/logs/tc0001/tomcat/tomcat7.1/conf/catalina.properties:app.env.server.name = demo.example.com
/logs/tc0001/tomcat/tomcat7.2/conf/catalina.properties:app.env.server.name = quest.example.com
/logs/tc0001/tomcat/tomcat7.5/conf/catalina.properties:app.env.server.name = www.example.com

Ở đầu ra trên tôi muốn trích xuất 3 trường (Số 2, 4 và trường cuối cùng *.example.com). Tôi nhận được đầu ra sau đây:

cat file | awk -F'/' '{print $3 "\t" $5}'
tc0001   tomcat7.1
tc0001   tomcat7.2
tc0001   tomcat7.5

Làm cách nào để tôi cũng trích xuất trường cuối cùng với tên miền nằm sau '='? Làm cách nào để sử dụng multiple delimiterđể trích xuất trường?


2
Để trả lời câu hỏi của tôi giống nhau nhưng khác nhau, awklà nuốt các trường khi chúng trống để đánh số trường. Tôi đổi -F " "thành -F "[ ]"awkkhông nuốt những cánh đồng trống nữa.
Adam

Câu trả lời:


324

Dấu phân cách có thể là một biểu thức chính quy.

awk -F'[/=]' '{print $3 "\t" $5 "\t" $8}' file

Sản xuất:

tc0001   tomcat7.1    demo.example.com  
tc0001   tomcat7.2    quest.example.com  
tc0001   tomcat7.5    www.example.com

42
Tất nhiên, catquá trình không bắt buộc : awk '...' file. Ngoài ra, sẽ gọn gàng hơn khi sử dụng trình phân tách trường đầu ra:awk -F'[/=]' -v OFS="\t" '{print $3, $5, $8}'
glenn jackman

17
Dấu phân cách Awk có thể là biểu thức chính quy ... điều này làm cho ngày của tôi!
das.cyklone

4
@ das.cyklone: awk cũng có thể có nhiều dải phân cách, với |: ví dụ: awk -F 'this|that|[=/]' '......' (hữu ích để có lời / chuỗi tách thứ) (lưu ý rằng điều này sẽ giúp các không gian trong FIELS giữa 2 tách Thêm cũng có. |[ \t]+có thể hữu ích, nhưng có thể làm cho mọi việc khó khăn ... vì thường có khoảng trắng trước và sau 'cái này', điều này sẽ làm cho 2 trường trống thêm xuất hiện ở giữa (các) không gian và 'cái này')
Olivier Dulac

Tôi đã thử điều này trên 2 bản phát hành khác nhau và tôi có cùng một hành vi: Tôi muốn lấy cổng từ netstat -ntpl "netstat -ntpl | sed 's /: / /' | awk '{print $ 5}'" hoạt động nhưng có thể làm mà không cần đường ống doulbe Điều này hoạt động nhưng tôi không mong đợi dữ liệu trên trường 17: "netstat -ntpl | awk -F" |: "'{print $ 17}'"
louigi600

2
vâng ... điều này đã cho tôi những gì tôi muốn: awk -F "[:] +" '/ \ / postmaster * $ / {print $ 5}'
louigi600

44

Tin tốt! awkdấu tách trường có thể là một biểu thức chính quy. Bạn chỉ cần sử dụng -F"<separator1>|<separator2>|...":

awk -F"/|=" -vOFS='\t' '{print $3, $5, $NF}' file

Trả về:

tc0001  tomcat7.1  demo.example.com
tc0001  tomcat7.2  quest.example.com
tc0001  tomcat7.5  www.example.com

Đây:

  • -F"/|="đặt dấu tách trường đầu vào thành /hoặc =. Sau đó, nó đặt dấu tách trường đầu ra thành một tab.

  • -vOFS='\t'đang sử dụng -vcờ để thiết lập một biến. OFSlà biến mặc định cho Dấu tách trường đầu ra và nó được đặt thành ký tự tab. Cờ là cần thiết vì không có tích hợp cho OFS như thế nào -F.

  • {print $3, $5, $NF} in các trường thứ 3, 5 và cuối cùng dựa trên dấu tách trường đầu vào.


Xem một ví dụ khác:

$ cat file
hello#how_are_you
i#am_very#well_thank#you

Tập tin này có hai dấu phân cách trường #_. Nếu chúng ta muốn in trường thứ hai bất kể dấu phân cách là cái này hay cái kia, hãy biến cả hai thành dấu phân cách!

$ awk -F"#|_" '{print $2}' file
how
am

Trong đó các tệp được đánh số như sau:

hello#how_are_you           i#am_very#well_thank#you
^^^^^ ^^^ ^^^ ^^^           ^ ^^ ^^^^ ^^^^ ^^^^^ ^^^
  1    2   3   4            1  2   3    4    5    6

1
Cảm ơn @BUFU đã chỉnh sửa của bạn. Tôi đã xóa tham chiếu OFS để chỉ tập trung vào phần FS, nhưng cũng tốt để có nó. Chúc mừng!
fedorqui 'SO ngừng gây hại'

5

Nếu khoảng trắng của bạn nhất quán, bạn có thể sử dụng nó làm dấu phân cách, thay vì chèn \ttrực tiếp, bạn có thể đặt dấu tách đầu ra và nó sẽ được bao gồm tự động:

< file awk -v OFS='\t' -v FS='[/ ]' '{print $3, $5, $NF}'

3

Đối với dấu phân cách trường của bất kỳ số nào 2thông qua 5hoặc chữ cái ahoặc #hoặc khoảng trắng, trong đó ký tự phân tách phải được lặp lại ít nhất 2 lần và không quá 6 lần, ví dụ:

awk -F'[2-5a# ]{2,6}' ...

Tôi chắc chắn các biến thể của điều này tồn tại bằng cách sử dụng () và tham số


3

Perl một lớp lót:

perl -F'/[\/=]/' -lane 'print "$F[2]\t$F[4]\t$F[7]"' file

Các tùy chọn dòng lệnh này được sử dụng:

  • -nlặp xung quanh mỗi dòng của tệp đầu vào, đặt dòng vào $_biến, không tự động in mọi dòng

  • -l xóa các dòng mới trước khi xử lý và thêm chúng trở lại sau đó

  • -achế độ autosplit - perl sẽ tự động phân chia các dòng đầu vào thành @Fmảng. Mặc định để phân tách trên khoảng trắng

  • -Fsửa đổi tự động, trong ví dụ này chia tách một trong hai /hoặc=

  • -e thực thi mã perl

Perl có liên quan chặt chẽ với awk, tuy nhiên, @Fmảng autosplit bắt đầu tại chỉ mục $F[0]trong khi các trường awk bắt đầu bằng $ 1.


2

Một cách khác là sử dụng tùy chọn -F nhưng vượt qua regex để in văn bản giữa dấu ngoặc trái và phải ().

Nội dung tập tin:

528(smbw)
529(smbt)
530(smbn)
10115(smbs)

Lệnh:

awk -F"[()]" '{print $2}' filename

kết quả:

smbw
smbt
smbn
smbs

Sử dụng awk để chỉ in văn bản giữa []:

Sử dụng awk -F'[][]' nhưng awk -F'[[]]'sẽ không hoạt động.

http://stanlo45.blogspot.com/2020/06/awk-multipl-field-separators.html


Câu trả lời của bạn xuất hiện trong hàng đợi xóa vì 9 lần trong số 10, người dùng có 1 danh tiếng liên kết đến blog của họ thường là thư rác. Nhưng của bạn là ngoại lệ cho quy tắc. 10 năm qua của nội dung có một mỏ vàng, hy vọng bạn có kế hoạch để bất tử nó.
Eric Leschinski

0

Tôi thấy nhiều câu trả lời hoàn hảo được đưa lên bảng, nhưng vẫn muốn tải lên đoạn mã của tôi,

awk -F"/" '{print $3 " " $5 " " $7}' sam | sed 's/ cat.* =//g'


2
print $3 " " $5 " " $7có thể được in như là print $3, $5, $7. Ngoài ra, tôi không thấy lợi thế của việc sử dụng awk và sau đó chuyển sang sử dụng sed. Nói chung, awk có thể đủ và những người khác trả lời cho thấy điều đó.
fedorqui 'SO ngừng làm hại'
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.