ใช้ awk กับเงื่อนไขค่าคอลัมน์


109

ฉันกำลังเรียนรู้ awk จากThe AWK Programming Languageและฉันมีปัญหากับหนึ่งในตัวอย่าง

ถ้าฉันต้องการพิมพ์ $ 3 ถ้า $ 2 เท่ากับค่า (เช่น1) ฉันใช้คำสั่งนี้ซึ่งใช้ได้ดี:

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

แต่เมื่อฉันแทนที่ 1 ด้วยเกณฑ์การค้นหาอื่น (เช่นfindtext) คำสั่งไม่ทำงาน:

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

มันไม่ส่งคืนผลลัพธ์และฉันแน่ใจว่ามี 'findtext' อยู่ในไฟล์อินพุต

ฉันลองสิ่งนี้ด้วย แต่ไม่ได้ผล:

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

นี่คือไฟล์ทดสอบของฉันชื่อ 'test' และมี 9 บรรทัดและ 8 ฟิลด์คั่นด้วยช่องว่าง:

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

นี่คือสิ่งที่ฉันทำและผลลัพธ์:

$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

ฉันคาดว่าจะได้เห็นสิ่งนี้ซึ่งเป็น 3 ดอลลาร์ที่มี "ClNonZ" อยู่ที่ 8 ดอลลาร์

0.180467091 
0.010615711 
0.492569002

ไม่รู้ว่าทำไมคำสั่ง awk ไม่ส่งกลับอะไรเลย ความคิดใด ๆ ?


คุณต้องอ้างค่าสตริง "findtext" มิฉะนั้นจะเป็นชื่อตัวแปร
evil otto

ฉันลองใช้เครื่องหมายคำพูดคู่กับ "findtext" แต่ไม่ได้ผล .. นั่นเป็นสาเหตุที่ทำให้ฉันรำคาญ
user1687130

1
"ไม่ทำงาน" ไม่ได้บอกอะไรเรา แสดงอินพุตที่แน่นอนโค้ดที่แน่นอนเอาต์พุตที่คาดหวังและเอาต์พุตจริง
chepner

คำตอบ:


129

หากคุณกำลังมองหาสตริงเฉพาะให้ใส่เครื่องหมายคำพูดไว้รอบ ๆ :

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

มิฉะนั้น awk จะถือว่าเป็นชื่อตัวแปร


ฉันลองแล้ว แต่มันไม่ได้ผลฉันไม่รู้ว่าทำไม ฉันตรวจสอบด้วย grep อีกครั้งและมีข้อความอยู่ในนั้น :(
user1687130

1
@ user1687130 ฉันคิดว่าคุณจะต้องแสดงตัวอย่างอินพุตและผลลัพธ์ที่คาดหวังให้เราเห็น
Carl Norum

1
คุณแน่ใจหรือไม่ว่าข้อมูลของคุณแยกพื้นที่ ช่องว่างเหล่านั้นอาจเป็นแท็บหรือไม่ ลองใช้ awk เพื่อสะท้อนฟิลด์เดียว ไม่awk '{ print $8 }'ให้สิ่งที่คุณคาดหวัง?
Rob Davis

1
มันอาจจะเกิดจากAWKการดำเนินงาน (ตรวจสอบด้วยawk --version) ได้ดูคำตอบของฉันก็ทำงานในGAWKและMAWKมากเกินไป
arutaku

สิ่งนี้ใช้ไม่ได้เมื่อเราใช้เครื่องหมายคำพูดคู่รอบสคริปต์ awk Likeawk "$1 == \"findtext\" {print $3}"
Thirupathi Thangavel

34

วิธีนี้ใช้ regexp ควรใช้งานได้:

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

ขอบคุณฉันกำลังค้นหาวิธีใช้ awk เพื่อค้นหา regex บน $ NF โดยไม่ต้องใช้วิธี diabolic และ grep ^^
Thibault Loison

20

ขึ้นอยู่กับAWKการนำไปใช้งานที่คุณใช้ว่าใช้ได้==หรือไม่

คุณลอง~หรือยัง. ตัวอย่างเช่นหากคุณต้องการให้ $ 1 เป็น "สวัสดี":

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

^หมายถึง $ 1 start และ$$ 1 end


4
การใช้งาน awk ทั้งหมดรองรับทั้ง "==" และ "~"
Ed Morton

2
@EdMorton - OS X awkไม่สามารถจับคู่ได้==แต่ประสบความสำเร็จด้วย~.
jww

2
@jww ไม่สามารถจับคู่อะไรกับอะไร? สิ่งเหล่านี้เทียบเท่า: $1 == "hello"และ$1 ~ /^hello$/. คุณไม่ควรทำ$1 ~ "^hello$"ตามที่แสดงในคำตอบนี้เนื่องจากใช้สตริงในบริบท regexp ดังนั้น awk จึงต้องแปลงสตริงเป็น regexp ก่อนที่จะใช้และมีผลข้างเคียง (man awk)
Ed Morton


2

เวอร์ชัน awk ของฉันคือ 3.1.5

ใช่ไฟล์อินพุตถูกแยกพื้นที่ไม่มีแท็บ

ตามคำตอบของ arutaku นี่คือสิ่งที่ฉันลองแล้วได้ผล:

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


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

อะไรไม่ได้ผล (ฉันไม่รู้ว่าทำไมและอาจเป็นเพราะเวอร์ชัน awk ของฉัน :)

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

ขอบคุณทุกคนสำหรับคำตอบความคิดเห็นและความช่วยเหลือ!


9
สิ่งนี้ไม่มีส่วนเกี่ยวข้องกับเวอร์ชัน awk ของคุณ คุณสร้างไฟล์ทดสอบของคุณบน Windows ดังนั้นไม่ว่าคุณจะใช้เครื่องมือใดในการทำ control-M ที่ต่อท้ายแต่ละบรรทัดดังนั้นฟิลด์สุดท้ายในแต่ละบรรทัดจึงClNonZ<control-M>ไม่ใช่ClNonZเหตุใดจึงเป็นการเปรียบเทียบการจับคู่ RE บางส่วนเมื่อทำด้วย grep หรือ "~ "ใน awk พบ แต่การเปรียบเทียบความเท่าเทียมกันไม่พบ
Ed Morton

2
ใช่เข้าท่า ฉันลอง $ dos2unix test แล้วใช้ "==" เพื่อแทนที่ "~" และมันก็ใช้ได้ ขอบคุณสำหรับคำอธิบาย!
user1687130

-3

โปรดลองสิ่งนี้

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

หรือ

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

น่าเศร้าที่คำตอบนี้ไม่ได้ใช้ไวยากรณ์ Awk ที่ผู้ใช้ถามหาโดยเฉพาะ!
Asfand Qazi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.