sử dụng awk với các điều kiện giá trị cột


108

Tôi đang học awk từ Ngôn ngữ lập trình AWK và tôi gặp sự cố với một trong các ví dụ.

Nếu tôi muốn in $ 3 nếu $ 2 bằng một giá trị (ví dụ 1), tôi đang sử dụng lệnh này hoạt động tốt:

awk '$2==1 {print $3}' <infile> | more

Nhưng khi tôi thay thế 1 bằng một tiêu chí tìm kiếm khác, (ví dụ findtext), lệnh không hoạt động:

awk '$1== findtext {print $3}' <infile> | more

Nó không trả về đầu ra và tôi chắc chắn rằng 'findtext' tồn tại trên tệp đầu vào.

Tôi cũng đã thử điều này, nhưng nó không hoạt động:

awk '$1== "findtext" {print $3}' <infile> | more

Đây là tệp thử nghiệm của tôi có tên 'test' và nó có 9 dòng và 8 trường, được phân tách bằng dấu cách:

1 11 0.959660297 0 0.021231423 -0.0073 -0.0031 MhZisp
2 14 0.180467091 0.800424628 0 0.0566 0.0103 ClNonZ
3 19 0.98089172 0 0 -0.0158 0.0124 MhNonZ
4 15 0.704883227 0.265392781 0.010615711 -0.0087 -0.0092 MhZisp
5 22 0.010615711 0.959660297 0.010615711 0.0476 0.0061 ClNonZ
6 23 0.715498938 0 0.265392781 -0.0013 -0.0309 Unkn
7 26 0.927813163 0 0.053078556 -0.0051 -0.0636 MhZisp
8 44 0.55626327 0.222929936 0.201698514 0.0053 -0.0438 MhZisp
9 31 0.492569002 0.350318471 0.138004246 0.0485 0.0088 ClNonZ

Đây là những gì tôi đã làm và kết quả:

$awk '$8 == "ClNonZ" {print $3}' test 

$ grep ClNonZ test 
2 14 0.180467091 0.800424628 0 0.0566 0.0103 ClNonZ
5 22 0.010615711 0.959660297 0.010615711 0.0476 0.0061 ClNonZ
9 31 0.492569002 0.350318471 0.138004246 0.0485 0.0088 ClNonZ

Tôi mong đợi để xem đây là $ 3 có "ClNonZ" trong $ 8 của họ.

0.180467091 
0.010615711 
0.492569002

Không biết tại sao lệnh awk không trả về bất cứ điều gì. Có suy nghĩ gì không?


Bạn cần phải trích dẫn giá trị chuỗi "findtext", nếu không thì đó là một tên biến
ác otto

Tôi cố gắng dấu ngoặc kép với "findtext", nhưng nó không làm việc .. đó là lý do tại sao nó làm tôi bực mình
user1687130

1
"Không hoạt động" không cho chúng ta biết bất cứ điều gì. Hiển thị cho chúng tôi đầu vào chính xác, mã chính xác, đầu ra dự kiến ​​và đầu ra thực tế.
chepner

Câu trả lời:


128

Nếu bạn đang tìm kiếm một chuỗi cụ thể, hãy đặt dấu ngoặc kép xung quanh nó:

awk '$1 == "findtext" {print $3}'

Nếu không, awk sẽ cho rằng đó là một tên biến.


Tôi đã thử cách này nhưng không hiệu quả, tôi không biết tại sao. Tôi đã kiểm tra lại bằng grep và văn bản ở trong đó. :(
user1687130

1
@ user1687130, tôi nghĩ bạn sẽ cần cho chúng tôi xem một số ví dụ đầu vào và đầu ra dự kiến.
Carl Norum

1
Bạn có chắc chắn dữ liệu của bạn được phân tách bằng không gian. Có thể một số không gian trong số đó là tab? Hãy thử sử dụng awk để lặp lại một trường duy nhất. Có awk '{ print $8 }'cung cấp cho bạn những gì bạn mong đợi?
Rob Davis

1
Nó có thể là do AWKthực hiện (kiểm tra xem nó có awk --version), có một cái nhìn vào câu trả lời của tôi, nó hoạt động trong GAWKMAWKquá.
arutaku

Điều này không hoạt động khi chúng tôi sử dụng dấu ngoặc kép xung quanh tập lệnh awk. Thíchawk "$1 == \"findtext\" {print $3}"
Thirupathi Thangavel

33

Phương pháp này sử dụng regexp, nó sẽ hoạt động:

awk '$2 ~ /findtext/ {print $3}' <infile>

Cảm ơn Tôi đang tìm kiếm một cách để sử dụng awk để tìm regex trên $ NF mà không sử dụng phương pháp quỉ quyệt và grep ^^
Thibault Loison

20

Tùy thuộc vào cách AWKthực hiện mà bạn sử dụng ==có ok hay không.

Bạn đã thử ~chưa ?. Ví dụ: nếu bạn muốn $ 1 là "xin chào":

awk '$1 ~ /^hello$/{ print $3; }' <infile>

^có nghĩa là $ 1 bắt đầu và $là $ 1 kết thúc.


4
Tất cả các triển khai awk đều hỗ trợ cả "==" và "~".
Ed Morton

2
@EdMorton - awkKhông thể khớp với OS X ==nhưng đã thành công với ~.
jww

2
@jww Không thể khớp cái gì với cái gì? Chúng tương đương: $1 == "hello"$1 ~ /^hello$/. Bạn không bao giờ nên làm $1 ~ "^hello$"như được hiển thị trong câu trả lời này vì nó đang sử dụng một chuỗi trong ngữ cảnh regexp và vì vậy awk phải chuyển đổi chuỗi thành regexp trước khi sử dụng nó và điều đó có tác dụng phụ (man awk).
Ed Morton


2

Phiên bản awk của tôi là 3.1.5.

Có, tệp đầu vào được phân cách bằng dấu cách, không có tab.

Theo câu trả lời của arutaku, đây là những gì tôi đã thử đã hiệu quả:

awk '$8 ~ "ClNonZ"{ print $3; }' test  
0.180467091
0.010615711
0.492569002


$ awk '$8 ~ "ClNonZ" { print $3}' test  
0.180467091
0.010615711
0.492569002

Điều gì không hoạt động (Tôi không biết tại sao và có thể do phiên bản awk của tôi :),

$awk '$8 ~ "^ClNonZ$"{ print $3; }' test
$awk '$8 == "ClNonZ" { print $3 }' test

Cảm ơn tất cả các bạn đã trả lời, nhận xét và giúp đỡ!


9
Điều này không liên quan gì đến phiên bản awk của bạn. Bạn đã tạo tệp thử nghiệm của mình trên Windows nên bất kỳ công cụ nào bạn sử dụng để thực hiện điều khiển đó đều thêm điều khiển-Ms vào cuối mỗi dòng để trường cuối cùng trên mỗi dòng ClNonZ<control-M>không phải ClNonZlà lý do tại sao so sánh đối sánh từng phần RE như được thực hiện với grep hoặc "~ "trong awk tìm thấy nó nhưng so sánh bình đẳng thì không.
Ed Morton

2
Vâng, có lý. Tôi đã thử kiểm tra $ dos2unix và sau đó sử dụng "==" để thay thế "~" và nó hoạt động. Cảm ơn vì lời giải thích!
user1687130

-3

hãy thử cái này

echo $VAR | grep ClNonZ | awk '{print $3}';

hoặc là

echo cat filename | grep ClNonZ | awk '{print $3}';

Đáng tiếc là câu trả lời này không thực sự sử dụng cú pháp Awk mà người dùng đã yêu cầu cụ thể!
Asfand Qazi
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.