มี sed ละเว้นบรรทัดที่ไม่ตรงกัน


94

ฉันจะสร้างsedบรรทัดการจับคู่ตัวกรองตามนิพจน์บางส่วนได้อย่างไร แต่ไม่สนใจบรรทัดที่ไม่ตรงกันแทนที่จะปล่อยให้พิมพ์

ตามตัวอย่างจริงฉันต้องการเรียกใช้scalac(คอมไพเลอร์ Scala) ในชุดไฟล์และอ่านจาก-verboseผลลัพธ์ของ.classไฟล์ที่สร้างขึ้น scalac -verboseส่งออกข้อความจำนวนมาก แต่เราสนใจเฉพาะในรูปแบบ[wrote some-class-name.class]เท่านั้น สิ่งที่ฉันกำลังทำอยู่คือสิ่งนี้ ( |&เป็นวิธี bash 4.0 ในการไพพ์ stderr ไปยังโปรแกรมถัดไป)

$ scalac -verbose some-file.scala ... |& sed 's/^\[wrote \(.*\.class\)\]$/\1/'

การดำเนินการนี้จะดึงชื่อไฟล์ออกจากข้อความที่เราสนใจ แต่จะปล่อยให้ข้อความอื่น ๆ ผ่านไปโดยไม่เปลี่ยนแปลง! แน่นอนว่าเราสามารถทำสิ่งนี้แทนได้:

$ scalac -verbose some-file.scala ... |& grep '^\[wrote .*\.class\]$' |
  sed 's/^\[wrote \(.*\.class\)\]$/\1/'

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


2
คำตอบที่ยอมรับควรเป็นคำตอบโดย mouviciel: stackoverflow.com/a/1665574/869951
Oliver

คำตอบ:


90

อีกวิธีหนึ่งที่มีความเรียบง่าย:

sed -e 's/.../.../;t;d'

s///เป็นการทดแทนtโดยไม่มีป้ายกำกับใด ๆ ตามเงื่อนไขข้ามคำสั่งต่อไปนี้ทั้งหมดdจะลบบรรทัด

ไม่จำเป็นต้อง perl หรือ grep

(แก้ไขตามคำแนะนำของนิโคลัสไรลีย์)


3
บน OS X 10.8.2 ผมต้องแยกtxและมีการขึ้นบรรทัดใหม่มากกว่าอัฒภาคที่ผมได้รับd undefined label 'x;d;:x'
davidchambers

6
ดียิ่งขึ้น: sed -e 's/.../.../' -e 'tx' -e 'd' -e ':x'(แนะนำในความคิดเห็นเกี่ยวกับคำถามที่คล้ายกัน )
davidchambers

1
T sed -e 's/.../.../' -e 't' -e 'd''จะโอนไปยังจุดสิ้นสุดของสคริปต์ถ้าไม่มีป้ายจะถูกส่งให้เพื่อให้ง่าย:
Nicholas Riley

ผู้คนไม่ทราบความหมายของ-eตัวเลือกจึงไม่กล่าวถึงโดยทั่วไป
Fredrick Gauss

246

หากคุณไม่ต้องการพิมพ์บรรทัดที่ไม่ตรงกันคุณสามารถใช้การรวมกันของ

  • -n ตัวเลือกที่บอกให้ sed ไม่พิมพ์
  • p แฟล็กที่บอกให้ sed พิมพ์สิ่งที่จับคู่

สิ่งนี้ให้:

sed -n 's/.../.../p'

3
ข้อเสียอย่างหนึ่งของวิธีนี้คือหากคุณมีหลายนิพจน์ที่ตรงกันผลลัพธ์จะถูกพิมพ์หลายครั้ง ตัวอย่างเช่น: echo foo | sed -n -e 's/foo/bar/p' -e 's/bar/oof/p'จะแสดงทั้งสองบรรทัดbarและoofแยกกัน แม้ว่าความหลากหลายของป้ายกำกับ goto จะไม่สามารถรองรับหลายรูปแบบได้เนื่องจากจะลบบรรทัดหากรูปแบบแรกไม่ตรงกัน
Rapsey

@Rapsey นั่นเป็นเพราะคุณบอกให้พิมพ์สองครั้ง ในคำสั่ง sed เดียวที่คุณบอกให้พิมพ์สองครั้งแต่ละอินสแตนซ์จะถูกพิมพ์ในแหล่งกำเนิด (หรืออาจจะบัฟเฟอร์) คุณจะต้องไปป์แทน -e หรือใส่ 'p' ไว้ที่ -e สุดท้ายเท่านั้น
จุลินทรีย์

@Rapsey: ดูคำตอบของฉันเกี่ยวกับประเด็นที่เกี่ยวข้องนี้
Amessihel

@ จุลินทรีย์จะใช้ไม่ได้เนื่องจากแฟล็ก p สุดท้ายจะทำงานในแต่ละบรรทัดที่ตรงกันโดยนิพจน์การแทนที่สุดท้าย
Amessihel


0

Rapsey ยกประเด็นที่เกี่ยวข้องเกี่ยวกับนิพจน์การแทนที่หลายรายการ

  • ขั้นแรกให้อ้างคำตอบ Unix SEคุณสามารถ "นำหน้าคำสั่ง sed ส่วนใหญ่ด้วยที่อยู่เพื่อ จำกัด บรรทัดที่ใช้"
  • ประการที่สองคุณสามารถจัดกลุ่มคำสั่งภายในวงเล็บปีกกา{}(คั่นด้วยเครื่องหมายอัฒภาค;หรือบรรทัดใหม่)
  • ประการที่สามเพิ่มแฟล็กการพิมพ์pในการแทนที่ครั้งสุดท้าย

ไวยากรณ์:

sed -n -e '/^given_regexp/ {s/regexp1/replacement1/flags1;[...];s/regexp1/replacement1/flagsnp}'

ตัวอย่าง (ดูเอกสารที่นี่สำหรับรายละเอียดเพิ่มเติม):

  • รหัส:

    sed -n -e '/^ha/ {s/h/k/gp;s/a/e/g}' <<SAMPLE
    haha
    hihi
    SAMPLE
    
  • ผลลัพธ์:

    kaka
    

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