วิธี grep บรรทัดตามรูปแบบที่แน่นอน?


8

สมมติว่าฉันมีไฟล์ที่มีสองบรรทัดต่อไปนี้:

2014-05-05      09:11:53    /aa/bbbb/cccccc             29899
2014-05-05      09:12:17    /aa/bbbb/cccccc?dddddddd    16767 

ฉันต้องได้รับสายที่มีรูปแบบเท่านั้นฉันไม่จำเป็นต้องบรรทัดที่สองที่มีอักขระพิเศษเช่น/aa/bbbb/cccccc ?ddddddddตอนนี้เมื่อฉันพยายาม

grep '/aa/bbbb/cccccc' file

จากนั้นเลือกบรรทัดทั้งสอง ฉันต้องการสายเต็มดังนั้นจึงgrep -oไม่สามารถแก้ไขได้

สิ่งที่เป็นไปได้ในการใช้grepเพื่อให้เลือกเฉพาะบรรทัดแรกตามรูปแบบการค้นหา

คำตอบ:


7

ลองใช้คำสั่ง grep ด้านล่างซึ่งใช้พารามิเตอร์-P( Perl-regexp )

grep -P '(?<!\S)/aa/bbbb/cccccc(?!\S)' file
  • (?<!\S)การค้นหาเชิงลบนี้ยืนยันว่าอักขระที่นำหน้าสตริง/aa/bbbb/ccccccจะเป็นอักขระใด ๆ แต่ไม่ใช่อักขระที่ไม่ใช่ช่องว่าง

  • (?!\S) Lookahead เชิงลบอ้างว่าตัวละครที่ตามหลังการแข่งขันจะเป็นแบบใดก็ได้ แต่ไม่ใช่ตัวอักษรที่ไม่ใช่ช่องว่าง

อีก grep

 grep -E '(^|\s)/aa/bbbb/cccccc(\s|$)' file

ผ่านหลาม

script.py

#!/usr/bin/python3
import re
import sys
file = sys.argv[1]
with open(file, 'r') as f:
    for line in f:
        for i in line.split():
            if i == "/aa/bbbb/cccccc":
                print(line, end='')

script.pyบันทึกรหัสดังกล่าวข้างต้นในแฟ้มและชื่อเป็น จากนั้นดำเนินการสคริปต์ข้างต้นโดย

python3 script.py /path/to/the/file/you/want/to/work/with

ขอบคุณชาย Btw นี้สามารถทำได้โดยใช้ regex ปกติ / ขยายมากกว่า perl regex?
heemayl

1
เช่นเดียวกับ terdon ที่โพสต์คุณทำได้ง่ายๆgrep '/aa/bbbb/cccccc ' file
Avinash Raj

แต่ข้างต้นจะไม่พิมพ์บรรทัดที่มี/aa/bbbb/ccccccสตริงเท่านั้น
Avinash Raj

คุณสามารถจับคู่นั้นกับgrep -E '/aa/bbbb/cccccc(\s+|$)' file
terdon

อ๋อแบบนี้grep -E '(^|\s)/aa/bbbb/cccccc(\s|$)' file
Avinash Raj

10

วิธีที่ง่ายที่สุดคือการเพิ่มช่องว่างหลังจากรูปแบบของคุณ:

$ grep '/aa/bbbb/cccccc ' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

หรือเพื่อให้ตรงกับช่องว่างทุกประเภท:

$ grep  '/aa/bbbb/cccccc[[:space:]]' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

หรือ

$ grep -P '/aa/bbbb/cccccc\s+' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

หรือด้วยlookahead เชิงบวก :

$ grep -P '/aa/bbbb/cccccc(?=\s)' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

หรือด้วยlookahead เชิงลบ :

$ grep -P '/aa/bbbb/cccccc(?!\S)' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

หรือคุณสามารถย้อนกลับการแข่งขัน:

$ grep  -v 'c?' file
2014-05-05      09:11:53    /aa/bbbb/cccccc             29899

หรือเพื่อจับคู่บรรทัดที่ไม่มีสิ่งใดนอกจากรูปแบบของคุณ (ไม่มีช่องว่างต่อท้าย):

grep -P '/aa/bbbb/cccccc(\s+|$)' file 
grep -E '/aa/bbbb/cccccc(\s+|$)' file 

หรือคุณสามารถใช้สคริปต์ขนาดเล็ก:

  • ใน awk:

    $ awk '$3=="/aa/bbbb/cccccc"' file
    2014-05-05      09:11:53    /aa/bbbb/cccccc             29899
    

    หรือถ้าคุณไม่ทราบว่ามีรูปแบบของฟิลด์ใด

    $ awk '{for(i=1;i<=NF;i++){if($i=="/aa/bbbb/cccccc"){print}}}' file
    2014-05-05      09:11:53    /aa/bbbb/cccccc             29899
    
  • ในภาษา Perl

    $ perl -ane 'print if grep {$_ eq "/aa/bbbb/cccccc"} @F' file
    2014-05-05      09:11:53    /aa/bbbb/cccccc             29899
    

@terdon ในgrep -v 'c?' fileสาเหตุที่คุณไม่ใช้grep -v '?' fileเพราะไฟล์มีสองบรรทัดเท่านั้น
αғsнιη

@KasiyA จริงฉันแค่อยากจะรักษารูปแบบเล็กน้อย คุณค่อนข้างถูก แต่ในกรณีนี้grep -v '?'จะเพียงพอ
terdon

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