วิธี grep แถวที่มีค่าบางอย่างในคอลัมน์ที่เฉพาะเจาะจง


9

ฉันมีไฟล์ดังต่อไปนี้

  200.000    1.353    0.086
  200.250    1.417    0.000
  200.500    1.359    0.091
  200.750    1.423    0.000
  201.000    1.365    0.093
  201.250    1.427    0.000
  201.500    1.373    0.093
  201.750    1.432    0.000
  202.000    1.383    0.091
  202.250    1.435    0.000
  202.500    1.392    0.087
  202.750    1.436    0.000
  203.000    1.402    0.081
  203.250    1.437    0.001
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045  

ฉันต้องการ grep เฉพาะแถวที่มีในคอลัมน์แรกคือทศนิยม .000 และ. 500 เท่านั้นดังนั้นผลลัพธ์จะเป็นเช่นนี้

  200.000    1.353    0.086
  200.500    1.359    0.091
  201.000    1.365    0.093
  201.500    1.373    0.093
  202.000    1.383    0.091
  202.500    1.392    0.087
  203.000    1.402    0.081
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045  

2
มันดูง่ายพอ คุณได้ลองทำอะไรไปแล้ว รหัสของคุณมีปัญหาอะไร
John1024

อาจเป็นเรื่องง่ายสำหรับคุณ แต่ฉันลองด้วยgrep '.000' | grep '.005'แต่เรียงแถวที่มีค่าเท่ากันในคอลัมน์อื่น ๆ
Mohsen El-Tahawy

3
ดีมาก. คนที่นี่น่าสงสารมากถ้าคุณแสดงความพยายามอย่างซื่อสัตย์ในการแก้ปัญหาด้วยตัวเอง รหัสในความคิดเห็นของคุณแสดงให้เห็นว่า ในอนาคตหากคุณรวมความพยายามเช่นนั้นไว้ในคำถามของคุณคุณจะได้รับคำตอบที่ดีขึ้นเร็วขึ้น
John1024

คำตอบ:


14

คุณไม่ได้ใช้ grep awkใช้

"your data" | awk '$1 ~ /\.[05]00/'

ดีมาก. ตามที่เขียนรหัสขึ้นอยู่กับว่ามีตัวเลขสามหลักหลังจุดทศนิยม awk '$1 ~ /\.[05]0*$/'มันจะมีประสิทธิภาพมากขึ้นในการใช้งาน
John1024

1
@ John1024 ตามจริงแล้วการเขียนรหัสขึ้นอยู่กับว่ามีตัวเลขอย่างน้อยสามหลักหลังจุดทศนิยม ฉันจะเอียงไปข้างหน้าawk '$1 ~ /\.[05]00$/'ด้วยตัวเอง (ต้องการตัวเลขสามหลัก) เว้นแต่ฉันจะมีเหตุผลที่จะคิดว่าคาดว่าจะมีตำแหน่งทศนิยมผันแปรในอินพุต
Wildcard

2
@Wildcard หากมีมากกว่าสามรหัสอาจล้มเหลว ตัวอย่างเช่นecho 0.5001 | awk '$1 ~ /\.[05]00/'. มันทำงานได้อย่างน่าเชื่อถือถ้ามีตรงสาม
John1024

4
awk '$1 ~ /\.[50]00/ { print $0 }' myFile.txt

คอลัมน์แรก$1จะถูกจับคู่กับ/\.500|\.000/จุดที่มีการหลบหนีเป็นจุดตัวอักษรที่ไม่ regex ตัวละครที่~มีการแข่งขันบางส่วนและพิมพ์ทั้งบรรทัด$0


2
ไม่มีเหตุผลที่จะรวม{ print $0 }; นั่นคือการกระทำเริ่มต้นของ Awk
Wildcard

4

ฉันต้องการgrepเฉพาะแถวที่อยู่ในคอลัมน์แรกคือ .000 และ. 500

ความคิดแรกของฉัน

grep '^ *[0-9][0-9][0-9]\.[50]00' filename

ทดสอบด่วนโดยใช้ WSL

$ head testdata
              200.000    1.353    0.086
              200.250    1.417    0.000
              200.500    1.359    0.091
              200.750    1.423    0.000
              201.000    1.365    0.093
              201.250    1.427    0.000
              201.500    1.373    0.093
              201.750    1.432    0.000
              202.000    1.383    0.091
              202.250    1.435    0.000
$ grep '^ *[0-9][0-9][0-9]\.[50]00' testdata
              200.000    1.353    0.086
              200.500    1.359    0.091
              201.000    1.365    0.093
              201.500    1.373    0.093
              202.000    1.383    0.091
              202.500    1.392    0.087
              203.000    1.402    0.081
              203.500    1.412    0.073
              204.000    1.423    0.065
              204.500    1.432    0.055
              205.000    1.441    0.045

มีวิธีรัดกุมมากขึ้นในการแสดงสิ่งนี้

$ grep -E '^ *[0-9]{3}\.[50]00' testdata
              200.000    1.353    0.086
              200.500    1.359    0.091
              201.000    1.365    0.093
              201.500    1.373    0.093
              202.000    1.383    0.091
              202.500    1.392    0.087
              203.000    1.402    0.081
              203.500    1.412    0.073
              204.000    1.423    0.065
              204.500    1.432    0.055
              205.000    1.441    0.045

หากคอลัมน์แรกอาจมีส่วนอื่นที่ไม่ใช่จำนวนเต็ม 3 หลัก

grep -E '^ *[0-9]+\.[05]00' testdata

ภายใต้สถานการณ์บางคุณอาจจำเป็นต้องใช้ในสถานที่ของ[:digit:][0-9]

และอื่น ๆ

man grep เป็นเพื่อนของคุณ.


การใช้งานนี้ใช้grepง่ายกว่าของฉัน ฉันจะไม่ได้โพสต์คำตอบถ้าฉันได้เห็นสิ่งนี้ก่อน งานที่ดี!
Yokai

2

ขึ้นอยู่กับกรณีการใช้งานของคุณคุณอาจใช้การดำเนินการตัวเลขจริง:

$ awk '{a = $1 % 1} a == 0 || a == 0.5' /tmp/foo
  200.000    1.353    0.086
  200.500    1.359    0.091
  201.000    1.365    0.093
  201.500    1.373    0.093
  202.000    1.383    0.091
  202.500    1.392    0.087
  203.000    1.402    0.081
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045

ทดสอบกับ BSD awk (OSX El Capitan, 20070501) และ GNU awk 4.1.4


1
คำเตือน: การทดสอบความเท่าเทียมกันที่แน่นอนของ floating-point (ซึ่ง awk ใช้) มักจะให้ผลลัพธ์ 'ผิด' เว้นแต่ว่าค่าจะไม่มีส่วนที่เป็นเศษส่วน (และไม่ใหญ่เกินไปในขนาด) หรือส่วนที่เป็นเศษส่วนคือ 'binary' (ครึ่งเดียว ไตรมาส ฯลฯ ) ซึ่งเป็นจริงสำหรับข้อมูลใน Q นี้ แต่ไม่มากนักที่ปรากฏคล้ายกับมือใหม่
dave_thompson_085

1
@ dave_thompson_085 แน่นอน แต่ด้วยการเพ่งพิศคุณสามารถใช้เลขคณิตความแม่นยำโดยพลการยอมรับว่าฉันไม่ได้ใช้พวกเขาที่นี่
muru


2

ด้วยawk:

$>awk '$1%.5==0' data.tsv 
200.000 1.353   0.086
200.500 1.359   0.091
201.000 1.365   0.093
201.500 1.373   0.093
202.000 1.383   0.091
202.500 1.392   0.087
203.000 1.402   0.081
203.500 1.412   0.073
204.000 1.423   0.065
204.500 1.432   0.055
205.000 1.441   0.045

ด้วยmlr:

$>mlr --ifs tab --onidx filter '$1%.5==0' data.tsv 
200.000 1.353 0.086
200.500 1.359 0.091
201.000 1.365 0.093
201.500 1.373 0.093
202.000 1.383 0.091
202.500 1.392 0.087
203.000 1.402 0.081
203.500 1.412 0.073
204.000 1.423 0.065
204.500 1.432 0.055
205.000 1.441 0.045

2

ตกลงเพิ่มอีกเล็กน้อยในการบริจาคของฉัน แต่ฉันคิดว่ามันคุ้มค่า

ความต้องการที่จะตอบสนองต่อ OP เป็นคอลัมน์แรกที่มีค่าทศนิยมเป็น.000หรือ.500เท่านั้น ไม่มีข้อกำหนดสำหรับค่านำไม่ว่าจะเป็นตามช่วงหรือความยาว เพื่อความแข็งแรงมันไม่ควรจะสันนิษฐานว่าจะถูก จำกัด โดยอะไรยกเว้นว่าไม่มีอักขระที่ไม่ใช่ว่างก่อนคอลัมน์แรก (หรือก็ไม่คอลัมน์แรก) และว่าเนื้อหาของคอลัมน์แรกจะมีจุดทศนิยมที่., ในนั้นที่ไหนสักแห่ง

OP ต้องการใช้grepซึ่งจะพิมพ์ทั้งบรรทัดเมื่อพบคู่ที่ตรงกันดังนั้นสิ่งเดียวที่ต้องทำคือสร้างรูปแบบที่ตรงกับทั้งหมดและเฉพาะสิ่งที่ต้องการ

ความเรียบง่ายของตัวเองและไม่มีเหตุผลที่จะใช้sedหรือawkgrep สามารถจัดการแหล่งที่มาเป็นไฟล์หรือไพพ์

เพื่อgrepใช้ไฟล์grep '^[^.]*\.[05]0\{2\}\s' the_file.txt

ไปยังgrepจากไปป์ใช้my_command | grep '^[^.]*\.[05]0\{2\}\s'

รูปแบบคือ: ^เริ่มต้นที่จุดเริ่มต้นของบรรทัด; [^.]ตรงกับอักขระที่ไม่ใช่ทศนิยมใด ๆ *หลาย ๆ ครั้งที่เป็นไปได้ (รวมถึงไม่มี) \.ตรงกับจุดทศนิยม [05], จับคู่ทั้งห้าหรือศูนย์; 0\{2\}, จับคู่อีก 2 ศูนย์ (แบ็กสแลชก่อนวงเล็บปีกกาเปิดและปิดป้องกันเชลล์จากการพยายามที่จะขยายรั้ง); \s, จับคู่อักขระช่องว่าง (หมายถึงจุดสิ้นสุดของคอลัมน์ - เพื่อใช้ในกรณีการใช้งานที่แตกต่างกัน, แทนที่ด้วยตัวคั่นคอลัมน์, โดยทั่วไปคือคอมมา, เซมิโคลอน, เซมิโคลอนหรือแท็บ\t)

หมายเหตุว่านี้จะตรงกับว่าสิ่งที่ OP ถาม จะไม่ตรงกัน.5000หรือ.0000แม้ว่าจะเทียบเท่าตัวเลขเพราะรูปแบบค้นหาห้าหรือศูนย์ตามด้วยศูนย์อีก2ตามด้วยช่องว่าง หากนั่นเป็นสิ่งสำคัญคำตอบอื่น ๆ ทั้งหมดก็คือความล้มเหลวในการที่พวกเขาจะตรงกับจำนวนศูนย์ใด ๆ มากกว่า 1 หลังจากตัวเลขทดสอบ และยกเว้นคำตอบของ FloHim เองพวกเขาจะจับคู่ทุกอย่างในคอลัมน์ที่สองที่เริ่มต้น .000หรือ.500รวมถึง.0003และ.500Tและหนึ่งโดย FloHimself จะจับคู่สิ่งที่เทียบเท่ากับคณิตศาสตร์.0และ.5ไม่ว่าจะมีศูนย์อยู่กี่แห่ง อันสุดท้ายในขณะที่ไม่จับคู่สิ่งที่ OP ระบุไว้น่าจะตรงกับสิ่งที่ OP ต้องการอยู่แล้ว

ในที่สุดถ้าต้องการพลังและความเร็วของawkถึงแม้ว่า OP ขอgrepแล้วคำสั่งจะเป็น:

ด้วยไฟล์ awk '$1 ~ /[^.]\.[05]0{2}$/' the_file.txt

ด้วยท่อ my_command | awk '$1 ~ /[^.]\.[05]0{2}$/'


1

หากคุณยืนยันที่จะใช้ grep สิ่งนี้อาจใช้ได้ผลสำหรับคุณ ฉันบันทึกผลลัพธ์แรกที่คุณให้กับไฟล์ข้อความชื่อ "file.txt" แล้วใช้คำสั่งต่อไปนี้:

grep -e '2[^ ]*.000' file.txt & grep -e '2[^ ]*.500' file.txt

ซึ่งให้ผลลัพธ์ของ:

200.000    1.353    0.086
200.500    1.359    0.091
201.500    1.373    0.093
201.000    1.365    0.093
202.500    1.392    0.087
202.000    1.383    0.091
203.500    1.412    0.073
203.000    1.402    0.081
204.500    1.432    0.055
204.000    1.423    0.065
205.000    1.441    0.045

คุณไม่ต้องบันทึกผลลัพธ์ไปยังไฟล์ข้อความหากไฟล์นั้นมีอยู่แล้วในไฟล์ แต่ในกรณีที่มันไม่ได้ถูกบันทึกเป็นไฟล์คุณยังสามารถท่อข้อมูลลงในคำสั่ง grep ที่ฉันมีให้และมันควรจะทำงานอย่างน้อยจนถึงหมายเลขแรกมากในคอลัมน์แรกไม่เป็น2 2ณ จุดนี้คุณจะต้องอัพเดตคำสั่ง grep ด้วยตัวอักษรที่เหมาะสมเพื่อพิมพ์อย่างถูกต้อง

สิ่งที่เกิดขึ้นกับgrepคำสั่งคู่นี้คือสิ่งแรกที่grepถูกส่งไปยังพื้นหลังกับ&ผู้ประกอบการ ขณะที่มันถูกส่งไปยังพื้นหลังgrepคำสั่งถัดไปจะดำเนินการทันทีหลังจากนั้นให้ผลลัพธ์ที่เหมือนกัน สำหรับงานที่คุณจะต้องเสร็จสิ้นการทำได้อย่างง่ายดายมากขึ้นคุณควรทำตามตัวอย่างที่คนอื่น ๆ ได้รับและการใช้งานหรือแม้กระทั่งawksed

(แก้ไข)

นี่ไม่ใช่วิธีการใช้ grep ที่ดีที่สุดหรือมีประสิทธิภาพมากที่สุดสำหรับความต้องการของคุณ แต่มันก็เพียงพอแล้วสำหรับคุณที่จะเล่นรอบ ๆ และรับความรู้สึกที่ดีขึ้นสำหรับ grep


กระบวนการแรกจะทำงานในพื้นหลัง แต่ไม่ daemonized ซึ่งรวมถึงการทำงานในพื้นหลัง แต่ค่อนข้างมาก และไม่น่าเป็นไปได้มากที่จะสร้างผลผลิตในลำดับเดียวกันกับอินพุต แม้ในตัวอย่างที่ค่อนข้างเล็กของคุณมันผิดไปแล้วในบรรทัดที่สาม
dave_thompson_085

เขาไม่ได้พูดถึงว่าผลผลิตจะต้องอยู่ในลำดับที่เฉพาะเจาะจง เฉพาะที่จะต้องมีเฉพาะกับ.500และ.000ของคอลัมน์แรก หากจำเป็นต้องอยู่ในลำดับที่เฉพาะเจาะจงเช่นอย่างน้อยที่สุดถึงมากที่สุดที่สามารถทำได้อย่างง่ายดาย อย่างไรก็ตามตัวเลข 3 ตัวแรกของคอลัมน์แรกที่พิมพ์ออกมานั้นเรียงตามลำดับน้อยที่สุดไปหามากที่สุด นั่นคือผลของและ2[^ ]*.000 2[^ ]*.500มันค่อนข้างเหมาะสมกับสิ่งที่ OP ถาม
Yokai

โปรดสังเกตการแก้ไขของฉันเพื่อการปฏิเสธความรับผิดชอบต่อประสิทธิภาพของคำสั่งที่ฉันให้ไว้ด้วย
Yokai
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.