จะลบบรรทัดอื่น ๆ ใน Vim ได้อย่างไร?


100

ฉันต้องการลบบรรทัดอื่น ๆ ทั้งหมดออกจาก Vim buffer โดยเริ่มจากบรรทัดที่สองเช่นบรรทัดที่ 2, 4, 6 เป็นต้นตัวอย่างเช่นหากเนื้อหาของบัฟเฟอร์คือ:

aaa
bbb
ccc
ddd
eee
fff

จากนั้นหลังจากลบบรรทัดที่ต้องการแล้วควรกลายเป็น:

aaa
ccc
eee

คุณควรจะใช้มาโครได้: oreillynet.com/mac/blog/2006/07/…
Mark Wilkins

ฉันชอบความมั่งคั่งของคำตอบนี้ ชื่นชอบ
froggythefrog

คำตอบ:


106

คุณสามารถใช้มาโครสำหรับสิ่งนี้ ดำเนินการดังต่อไปนี้

  • เริ่มในโหมดคำสั่ง
  • ggไปที่จุดเริ่มต้นของไฟล์โดยการกด
  • qqกด
  • คลิกลูกศรลงแล้วกดddหลัง
  • qกด
  • กด 10000@q

PS: หากต้องการไปที่โหมดคำสั่งเพียงแค่กด Escape สองสามครั้ง


11
สมมติว่าไฟล์ของคุณมีความยาวน้อยกว่า 20,000 บรรทัดแน่นอน :-)
paxdiablo

3
จริงๆแล้วคุณผิดไมเคิล สิ่งนี้ใช้งานได้อย่างไม่มีที่ติเนื่องจาก VI จะหยุดเรียกใช้มาโครทันทีที่ถึงจุดสิ้นสุดของไฟล์ คุณสามารถทดลองใช้กับตัวอย่างด้านบนได้อย่างง่ายดาย
rui

1
เช่นเดียวกับมาโครใด ๆ ที่คุณต้องทำให้ถูกต้องในครั้งแรก แต่หลังจากนั้นคุณสามารถนำไปใช้กับไฟล์ใดก็ได้โดยพิมพ์ 10,000 @ q ไม่ว่าจะด้วยวิธีใดฉันเชื่อว่ามันเป็นเพียงเรื่องของรสนิยมดังนั้นฉันจะไม่เริ่มการถกเถียงทางปรัชญาอย่างแน่นอน :)
rui

3
ฉันชอบใช้ 'มาโคร' เมื่อใช้มาโครคุณจะ 'อธิบาย' ว่าคุณจะแก้ปัญหางานหนึ่ง ๆ อย่างไรและปล่อยให้ VIM ทำซ้ำให้คุณ RUI ฉันต้องการใช้ 'j' แทนปุ่มลูกศร
SolutionYogi

4
:g/^/+dจากผู้ใช้stackoverflow.com/users/254635/ib (ร้อง) เป็นวิธีที่ดีกว่าในการแก้ปัญหานี้
SergioAraujo

259

วิธีที่สง่างาม (และมีประสิทธิภาพ) ในการทำงานให้สำเร็จคือการเรียกใช้:+deleteคำสั่งลบบรรทัดตามบรรทัดปัจจุบันในทุกบรรทัดโดยใช้:globalคำสั่ง:

:g/^/+d

10
ทำไมคำตอบนี้จึงไม่ได้รับการโหวตเพิ่มขึ้น? สะอาดและเรียบง่าย หรือคุณสามารถลบบรรทัดแรกและเรียกใช้คำสั่งด้านบนเพื่อลบบรรทัดคี่ทั้งหมด
Usagi

3
@ อุซางิ: ขอบคุณ! ฉันรู้สึกแบบเดียวกันกับมัน และใช่คุณพูดถูกจริงๆ:1d|g/^/+dลบเส้นคี่
ib.

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

3
ฉันไม่รู้คำตอบนี้ทำให้ฉันออกไปเรียนรู้การตกปลาด้วยคำสั่ง: g (นั่นคือทำให้ฉันเป็น Google หน้านี้ - vim.wikia.com/wiki/Power_of_g )
snetch

1
และถ้าคุณตีเขาด้วยปลา ... แต่เดี๋ยวก่อนคำตอบที่ได้รับการยอมรับก็ไม่ได้อธิบายเช่นกัน ฉันไม่เห็นจุดใดในการสร้างเอกสารคำสั่งส่วนกลาง ฉันลืมวิธีใช้คำสั่ง global (ทั้งๆที่เป็นคนโบราณ) และพบว่าหน้านี้ googling เป็นประโยชน์ที่สุด
Isaac Rabinovitch

66

เราสามารถใช้:normalหรือ:normดำเนินการตามคำสั่งโหมดปกติที่กำหนด ที่มา

:%norm jdd

15
คำตอบนี้ไม่ได้รับความสนใจมากพออาจเป็นเพราะไม่มีคำอธิบายทั้งที่นี่และในเอกสารโกงที่เชื่อมโยงยุ่งเหยิง คำสั่ง norm รันคำสั่งโหมดปกติเทียบเท่ากับตัวอักษรที่ตามหลัง ตรงนี้มันก็วิ่ง j เพื่อเลื่อนลงมาและ dd เพื่อลบมัน นี่เป็นเรื่องทั่วไปสำหรับบรรทัด Xth โดยการเพิ่ม 'j มากขึ้นในกรณีนี้
imoatama

5
และ% เป็นชวเลขสำหรับ 1, $ (ดำเนินการคำสั่งต่อไปนี้จากบรรทัดที่ 1 ถึงจุดสิ้นสุด)
Lambart

3
ฉันสนใจว่าทำไม%norm ddjไม่ทำงานถ้าคุณต้องการลบแถวคี่
Cyker

10
:map ^o ddj^o
^o

นี่ ^ ย่อมาจาก CTRL มาโครแบบเรียกซ้ำเพื่อลบบรรทัดทุกๆสองบรรทัด เลือกบรรทัดแรกของคุณให้ดีและเสร็จสิ้น


8

จากไฟล์เก็บถาวรของ vim mail :

:let i=1 | while i <= line('$') | if (i % 2) | exe i . "delete" | endif | let i += 1 | endwhile

(หากต้องการพิมพ์ในบรรทัดเดียวบนบรรทัดคำสั่งกลุ่มจะลบแถวที่ 1,3,5,7, ... )


4
ถ้าอย่างนั้นฉันต้องการ!perl -ne 'print unless $. % 2':-)
Alex Brasetvik

และอเล็กซ์ฉันต้องการวิธีแก้ปัญหาของฉันกับคุณอย่างแน่นอน แต่สิ่งนี้ควรค่าแก่การพิจารณาเนื่องจากนี่เป็นทางออกเดียวที่สมเหตุสมผลโดยใช้เพียงกลุ่มเดียวที่นี่
Michael Krelin - แฮ็กเกอร์

วิธีมาโครนั้นง่ายกว่ามาก
trusktr

+1 เนื่องจากความยืดหยุ่นif (expression)ซึ่งใช้ได้กับทุกบรรทัดที่สามเป็นต้น
Jens

5

คุณสามารถไพพ์คำสั่งเชลล์ได้ตลอดเวลาซึ่งหมายความว่าคุณสามารถใช้ภาษาสคริปต์ใดก็ได้ที่คุณต้องการ:

:%!perl -nle 'print if $. % 2'

(หรือใช้ "เว้นแต่" แทน "if" ขึ้นอยู่กับบรรทัดที่คุณต้องการ)


คุณไม่จำเป็นต้อง-lเปลี่ยนไปใช้ Perl ... นอกจากนี้ฉันจะบอกว่าawkมันแพร่หลายกว่า Perl เล็กน้อยแม้ว่าในปัจจุบันจะไม่มากนักและสามารถทำได้สั้นกว่านี้: :%!awk NR\%2หรือ:%!awk 1-NR\%2สำหรับบรรทัดอื่น ๆ
ephemient

4
:%!awk -- '++c\%2'

หรือ

:%!awk -- 'c++\%2'

ขึ้นอยู่กับว่าคุณต้องการกำจัดวัชพืชออกไปครึ่งหนึ่ง


อืมทำไมไม่ใช้NRตัวแปรที่มีอยู่ล่ะ
ephemient

ขวา. เพราะลืมไปแล้ว. ;-) แต่จริงๆแล้วตัวแปรที่ "เหมาะสม" จะใช้กับ NR ได้นานกว่าด้วย และจะไม่มีคู่ที่หน้าตาดีสองคน
Michael Krelin - แฮ็กเกอร์

:%!awk NR\%2หรือ:%!awk 1-NR\%2ตามที่ฉันโพสต์ในความคิดเห็นอื่น แทบจะไม่นาน
ephemient

1
1-NRc++มีความยาวมากกว่า ใช่ฉันรู้ว่ามันเป็นตัวละครเดียว อย่างที่ฉันพูด - เหตุผลที่แท้จริงคือฉันลืมมันไป อย่างไรก็ตามดูเหมือนว่าผู้คนจะไม่ชื่นชมความงามของ awk ที่นี่
Michael Krelin - แฮ็กเกอร์

และNRสั้นกว่า++c:)
ephemient

3

คุณสามารถใช้ความสามารถในการค้นหาและทดแทนของ Vim ได้ดังนี้: วางเคอร์เซอร์ไว้ที่บรรทัดแรกแล้วพิมพ์ในโหมดปกติ:

:.,/fff/s/\n.*\(\n.*\)/\1/g
  • .,/fff/เป็นช่วงสำหรับการทดแทน หมายความว่า "จากบรรทัดนี้ไปยังบรรทัดที่ตรงกับ regex fff(ในกรณีนี้คือบรรทัดสุดท้าย)
  • s///คือคำสั่งแทนที่ ค้นหา regex และแทนที่ทุกครั้งที่เกิดขึ้นด้วยสตริง gที่หมายถึงการสิ้นสุดการทำซ้ำเปลี่ยนตัวตราบเท่าที่ regex ทำให้ถูกพบ
  • regex จะ\n.*\(\n.*\)จับคู่ขึ้นบรรทัดใหม่จากนั้นทั้งบรรทัด ( .*จับคู่อักขระจำนวนเท่าใดก็ได้ยกเว้นขึ้นบรรทัดใหม่) จากนั้นขึ้นบรรทัดใหม่อีกบรรทัดและอีกบรรทัด วงเล็บ\(และก่อให้เกิดการแสดงออกภายในพวกเขาจะได้รับการบันทึกไว้เพื่อให้เราสามารถใช้งานได้ในภายหลังโดยใช้\)\1
  • \1 แทรกบรรทัดใหม่ที่จัดกลุ่มและบรรทัดหลังกลับเพราะเราไม่ต้องการให้บรรทัดถัดไปหายไปเราแค่ต้องการให้กลไกการแทนที่ผ่านไปดังนั้นเราจะไม่ลบมันในการแทนที่ครั้งถัดไป

ด้วยวิธีนี้คุณสามารถควบคุมช่วงที่คุณต้องการให้การลบเกิดขึ้นและคุณไม่ต้องใช้เครื่องมือภายนอกใด ๆ


หรือ$แทนที่จะ/fff/เป็น end-of-file โดยไม่คำนึงถึงเนื้อหาของไฟล์
ephemient

3

อีกวิธีหนึ่งคุณสามารถใช้ python ได้หาก vim ของคุณรองรับ

:py import vim; cb = vim.current.buffer; b = cb[:]; cb[:] = b[::2]

b = cb[:]bสำเนาทุกบรรทัดในบัฟเฟอร์ปัจจุบันชั่วคราว ได้รับทุกบรรทัดที่สองจากกันชนและกำหนดให้บัฟเฟอร์ปัจจุบันทั้งหมดb[::2] cb[:]การคัดลอกbเป็นสิ่งที่จำเป็นเนื่องจากวัตถุบัฟเฟอร์ดูเหมือนจะไม่รองรับไวยากรณ์ของสไลซ์ที่ขยายออกไป

นี่อาจไม่ใช่ "vim way" แต่อาจจำได้ง่ายกว่าถ้าคุณรู้จัก python


2

ในการลบเส้นคี่ (1,3,5, .. ) -> :%s/\(.*\)\n\(.*\)\n/\2\r/g

ในการลบเส้นคู่ (2,4,6, .. ) -> :%s/\(.*\)\n.*\n/\1\r/g

ค้นหาข้อความ (สร้างบรรทัดแรก) ตามด้วยอักขระบรรทัดใหม่และข้อความเพิ่มเติมบางส่วน (สร้างบรรทัดที่สอง) ตามด้วยอักขระบรรทัดใหม่อื่นและแทนที่ด้านบนด้วยการจับคู่แรก (บรรทัดคี่) หรือการจับคู่ที่สอง (เส้นคู่) ตามด้วยการคืนรถ


0

เรียก sed:

:% !sed -e '2~2 d'

^^^^                  pipe file through a shell command
    ^^^^^^            the command is sed, and -e describes an expression as parameter
            ^^^^^     starting with the second line, delete every second line

-1

วิธีการแก้

คุณสามารถลองสิ่งนี้ในกลุ่ม

:1,$-1g/^/+1d

แก้ไข

ฉันจะพยายามให้ชัดเจนมากขึ้น (สองส่วน)

ส่วนแรกช่วงการเลือก ( :from,to)
ส่วนที่สองการกระทำ ( dลบ)

  • ช่วงถ้าจากบรรทัดแรกถึงบรรทัดสุดท้าย แต่มีบรรทัดเดียว ( :1,$-1)
  • globaly ( g) ลบ ( +1d) บรรทัดถัดไป

คุณสามารถลองย้ายไปที่บรรทัดแรกของไฟล์และดำเนินการ:+1dคุณจะเห็นว่าบรรทัดถัดไปหายไป

ฉันรู้ว่ามันเป็นโคลน แต่มันก็เป็นกลุ่มและใช้งานได้


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