วิธีลบทุกบรรทัดที่สองจากไฟล์ได้อย่างไร


25

ไฟล์:

Data inserted into table. Total count 13
No error occurred
Data inserted into table. Total count 45
No error occurred
Data inserted into table. Total count 14
No error occurred
Data inserted into table. Total count 90
No error occurred

ไฟล์เอาต์พุตที่คาดหวัง:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90

ฉันต้องการให้เอาต์พุตมองด้วยวิธีนี้: ทุกบรรทัดที่สองจะถูกลบ แต่จะไม่มีช่องว่างระหว่างบรรทัด


5
คุณต้องการลบทุกบรรทัดที่สองหรือทุกบรรทัดที่มี"ไม่มีข้อผิดพลาดเกิดขึ้น"หรือไม่? เกิดอะไรขึ้นถ้าทั้งสองสายติดต่อกันได้"ไม่มีข้อผิดพลาดที่เกิดขึ้น" ?
Tulains Córdova

1
@ user1598390 ฉันคิดว่า ... ในกรณีgrep -v "No error occurred" fileนี้คำสั่งนี้จะทำงาน ... สิ่งที่ @paul ได้ตอบ ในไฟล์ที่ส่งออกจะไม่มีบรรทัดที่มี "ไม่มีข้อผิดพลาดเกิดขึ้น" ส่วนนี้
pmaipmui

1
จากนั้นชื่อของคำถามจะทำให้เข้าใจผิด
Tulains Córdova

คำตอบ:


36

ด้วยsed:

sed -e n\;d <file

ด้วย POSIX awk:

awk 'FNR%2' <file

หากคุณมีอายุมากกว่าawk(เช่นoawk) คุณต้อง:

oawk 'NR%2 == 1' <file

ด้วยex:

$ ex file <<\EX
:g/$/+d
:wq!
EX

จะแก้ไขไฟล์ในตำแหน่ง

  • g ทำเครื่องหมายคำสั่งทั่วโลก
  • /$/ ตรงกับทุกบรรทัด
  • +d ลบบรรทัดถัดไป
  • wq! บันทึกการเปลี่ยนแปลงทั้งหมด

วิธีการนี้ใช้อุดมคติเดียวกันกับsedวิธีการลบทุกบรรทัดถัดไปของบรรทัดปัจจุบันโดยเริ่มจากบรรทัดที่ 1

ด้วยperl:

perl -ne 'print if $. % 2' <file

และperl6:

perl6 -ne '.say if $*IN.ins % 2' <file
perl6 -ne '.say if ++$ % 2' <file

ใช่ ... มันใช้งานได้ ... :) ... อันแรกกำลังทำงาน .... ฉันได้ลองอันที่สองแล้ว .. มันบอกว่า `awk: ข้อผิดพลาดทางไวยากรณ์บรรทัดที่ 1 awk: การประกันตัวออกไปใกล้กับบรรทัดที่ 1 '
pmaipmui

sed -en \; d <file ~ ใช่มันใช้งานได้ @cuonglm ...
pmaipmui

1
ฉันเดาว่าคุณใช้n\;dแทนที่จะ'n;d'บันทึกตัวละครล้ำค่า แต่ตรรกะนั้นออกไปนอกหน้าต่างเมื่อคุณไม่จำเป็นต้องใช้-eสวิตช์และการเปลี่ยนเส้นทางไฟล์<!
Tom Fenech

1
@Geek: มันเป็นเวอร์ชั่นที่สั้นกว่าsed -e 'n;d'ช่วยให้คุณประหยัดตัวละครตัวหนึ่ง
cuonglm

1
@Geek: nคำสั่งเขียนพื้นที่รูปแบบเพื่อออกมาตรฐานถ้า-nมีการใช้แล้วแทนที่พื้นที่รูปแบบด้วยบรรทัดถัดไป ที่นี่ทุก ๆ เส้นคี่จะถูกพิมพ์โดยnแม้กระทั่งเส้นแล้วอ่านในพื้นที่รูปแบบ แต่ลบทันทีโดยdcommand`
cuonglm

62

การแก้ปัญหานี้โดยการลบทุกบรรทัดที่สองอาจเกิดข้อผิดพลาดได้ง่ายขึ้น (ตัวอย่างเช่นเมื่อบางครั้งกระบวนการบางครั้งสร้างสองบรรทัดที่มีความหมายแทนหนึ่ง) อาจดีกว่าถ้าจะกรองขยะ:

grep -v "No error occurred" file

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


9
+1 สำหรับการชี้ให้เห็นว่าบางครั้งบรรทัดที่สองมีความสำคัญ!
Kaz Wolfe

12

ถามคำถามด้วย GNU sed:

sed '0~2d' file

จะลบทุกบรรทัดที่สอง แต่ฉันต้องการเสนอตัวกรองตามเนื้อหา:

sed '/Data/! d' file

หรือด้วยผลลัพธ์เดียวกัน

sed '/No error/d' file

sed '/ ไม่มีข้อผิดพลาด / d' ไฟล์ ~ ให้ผลลัพธ์ที่ต้องการ @Costas
pmaipmui

5
โปรดทราบว่าสองคนสุดท้ายเป็นวิธีที่ซับซ้อนในการเขียนgrep Dataและgrep -v 'No error'
Stéphane Chazelas

5

นี่คือวิธีใช้sed:

sed -n 'p;n' filename

อีกวิธีด้วย GNU sed:

sed -n '1~2p' filename

เอาต์พุตจากคำสั่งด้านบน:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90

คุณหมายถึงอะไรเมื่อพูดshortest way using sed?
cuonglm

เหตุผลในการgออกคำสั่งคืออะไร? sed -n 'p;n'ก็เพียงพอแล้ว
Costas

@cuonglm: ฉันหมายถึงพูดง่ายๆในการทำ โดยวิธีลบคำนั้น :)
serenesat

@Costas: ขอบคุณ! gเพียงแค่การตรวจสอบการทำงานของตนโดยไม่ต้อง ลบ g จากคำสั่ง :)
serenesat

4

คุณสามารถลองด้วยawk:

awk 'NR % 2 != 0' file

หรือคุณสามารถพิมพ์เฉพาะบรรทัดที่มีData inserted:

awk '$0 ~ /Data inserted/' file

ฉันลองตอบคุณทั้งคู่แล้วและทั้งคู่ก็ทำงาน ... :)
pmaipmui

3

อีกคำตอบคุณสามารถใช้ vi / vim!

qdjddq

และถ้าไฟล์ของคุณเป็น 500 บรรทัด (ตัวอย่าง) ให้พิมพ์

250 @ d

จากนั้นให้เขียนและออกจากประเภท

: x

หรือหากมีบางอย่างผิดปกติและคุณไม่ต้องการบันทึก:

: Q!

คำอธิบาย:

q      #Start Recording
 d     #Put the recording into register 'd'
  j    #Move the cursor down
   dd  #Delete the line
     q #Stop recording


250    #Number of repeats
   @d  #Playback the recording in register 'd'.

2

นี่เป็นวิธีที่แตกต่างในการทำ:

< file paste - - | cut -f1

สมมติว่าบรรทัดที่มีเลขคี่ไม่มีแท็บ หากเป็นเช่นนั้นคุณจะต้องเลือกตัวคั่นอื่นเช่น:ที่นี่:

< file paste -d: - - | cut -d: -f1

1
ฉันมีสิ่งนี้อยู่ในใจเมื่อฉันเห็นคำถามครั้งแรก ... มันน่าสนใจที่จะทำการทดสอบความเร็วกับsedไฟล์ขนาดใหญ่ (เช่น 20 ล้านบรรทัด) อย่างไรก็ตาม +1 แต่จริงๆแล้วเพื่อหลีกเลี่ยงอาการปวดหัวให้เลือกตัวคั่นที่ไม่น่าจะเกิดขึ้นในไฟล์ข้อความเช่น$'\002'...
don_crissti

@don_crissti ใช่การใช้อักขระที่ไม่ได้พิมพ์สำหรับตัวคั่นเป็นความคิดที่ดี และใช่นี่วัดได้เร็วกว่าสารละลาย sed seq 100000000 > 100mil.txtฉันสร้างไฟล์ทดสอบด้วย การpaste|cutแก้ปัญหาเสร็จสิ้นในเวลาประมาณ 7.5 วินาทีเทียบกับเกือบ 12 สำหรับการsedแก้ปัญหา ดูเหมือนว่าจะทำซ้ำได้ grepแม้ว่าจะเร็วที่สุด Ubuntu 14.04 พร้อมด้วยเครื่องมือ GNU มาตรฐาน
บาดเจ็บทางดิจิทัล

อ๋อpaste+ cutจะเหมาะอย่างยิ่งสำหรับการทำงานของพวกเขาจึงไม่น่าแปลกใจรวมกันของพวกเขาคือสวยเหี้ยอย่างรวดเร็ว ...
don_crissti

1

ตัวเลือกอื่น (สั้นกว่า)

sed 'n; d' file

3
มันนานกว่าของฉันsed n\;dการเพิ่ม-eเป็นเพียงนิสัยของฉัน
cuonglm

0

นอกจากนี้ยังแก้ปัญหาแม้ว่าจะช้าลงเล็กน้อย:

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