Hapus n baris lewati 1 baris skrip

10

Saya ingin membuat skrip Vim dasar yang hanya menghapus n baris, melompati 1 baris dan mengulangi hingga akhir dokumen. Saya tidak peduli dengan pertandingan tertentu, saya hanya ingin menghapus garis. Sebagai contoh; Jadi saya ingin mengulangi perintah 3ddjuntuk seluruh dokumen.

Text I want to keep.   
Text I want to delete.  
Text I want to delete.  
Text I want to delete.  
Text I want to keep.  
Text I want to delete.  
Text I want to delete.  
Text I want to delete.  
Text I want to keep.  
Text I want to delete.  
Text I want to delete.  
Text I want to delete.   

Jadi sepertinya ...

Text I want to keep.  
Text I want to keep.  
Text I want to keep.  

Terima kasih.

Max Copley
sumber
Anda memasukkan tag regular-expressionpada pertanyaan Anda, tetapi pertanyaan itu tampaknya tidak menentukan alasan untuk melakukan ini dengan ekspresi reguler. Jika Anda benar-benar mencari sesuatu yang memang menggunakan ekspresi reguler, stackoverflow.com/questions/17735289/… mungkin menarik. Pertanyaan itu adalah tentang Notepad ++, tetapi jawabannya tidak menggunakan apa pun kecuali regre pcre. (Penafian: Saya menulis jawaban itu.)
Jasper
Lain kali Anda mengajukan pertanyaan, tidak perlu menulis "Terima kasih untuk ini. Solusi hebat!" pada setiap jawaban. Ini bahkan ditulis ketika Anda mencoba membuat komentar baru pada jawaban.
pipa
Untuk menambah itu, cara yang tepat untuk menunjukkan penghargaan di sini adalah dengan menerima jawaban yang paling cocok untuk Anda dan meningkatkan setiap jawaban yang Anda anggap bermanfaat atau berguna. Orang lebih suka melihat itu daripada komentar "terima kasih".
B Layer

Jawaban:

19

Pendekatan yang sangat sederhana:

  1. Pindah ke baris pertama yang ingin Anda hapus.
  2. Rekam makro: qa3ddjq
  3. Ulangi dengan angka tinggi: 1000 @ a

Langkah tiga akan mengulangi makro seribu kali atau sampai kesalahan terjadi. Memukul ujung file (karenanya tidak ada baris untuk dihapus) menghasilkan kesalahan dan pengulangan makro dibatalkan.

Lihat :help recording.

Ralf
sumber
2
Itu luar biasa!!! Terima kasih banyak, itu berhasil untuk saya: D
Max Copley
1
penjelasan: q(dalam mode perintah, dan dalam vim atau versi alternatif terbaru lainnya [neovim, dll], tetapi tidak dalam vi asli) berarti "mulai merekam, dan letakkan di buffer 'huruf berikutnya'". karenanya: qaberarti "mulai merekam ke dalam buffer 'a'". Kemudian setiap tombol yang diketik setelah ini (hingga qmode perintah berikutnya ) direkam (Anda bahkan dapat merekam: masuk ke mode edit, mengetikkan sesuatu, Melarikan diri ke mode perintah, dll). Kemudian 12@aakan mengulangi tindakan apa pun yang dicatat dalam buffer "a" 12 kali.
Olivier Dulac
3
Selain itu, jika Anda tidak ingin menjalankan sesuatu seperti 1000@qpada akhirnya, Anda dapat membuat makro rekursif:, qa3ddj@aq@ameskipun Anda mungkin perlu melakukan qaqterlebih dahulu untuk memastikan "amulai kosong.
James
17

Solusi termudah bagi saya adalah:

:%norm j3dd

Itu adalah:

  • %: untuk setiap baris
  • norm: jalankan kunci berikut seolah-olah dalam mode normal
  • j3dd: turunkan baris kemudian hapus 3 baris

Jadi dari baris pertama, turun ke yang kedua dan hapus 3 baris berikutnya. Yang kedua Text I want to keep.sekarang di baris kedua. Turun satu baris, hapus 3. Bilas dan ulangi.


Catatan: jika Anda tidak ingin memproses seluruh file, Anda dapat mengganti %normdengan misalnya 5,$normuntuk memproses dari baris ke-5 hingga akhir file.

Marth
sumber
4
Alternatif yang sangat bagus! Bekerja dalam vim (bukan vi). Saya tidak pernah mendengar tentang "norma" sebelumnya! (dan saya agak aneh)
Olivier Dulac
6

Anda memiliki beberapa solusi hebat yang sudah tersedia. Ini satu lagi:

:g/^/if line('.')%4!=1|:s/^/DELETE ME/|endif
:g/^DELETE ME/d

Pertama, kami melakukan tindakan pada setiap baris ( :gcocok dengan ^(awal baris)) dan untuk setiap nomor baris melakukan hasil linenumber % 4. Jika hasilnya tidak sama dengan 1, kami menambahkan DELETE MEdi awal baris, menandai baris yang akan dihapus oleh perintah berikutnya.

Perintah selanjutnya adalah perintah reguler ( :g), yang cocok dengan semua baris yang dimulai dengan DELETE MEdan melakukannya.

Catatan, Anda tidak dapat langsung menghapus baris menggunakan :gperintah pertama , karena ini akan mengubah perhitungan modulo yang dihasilkan dan karenanya, kita harus terlebih dahulu menandai baris dan pada langkah kedua menghapusnya.

Christian Brabandt
sumber
4

Saya tahu ini visalurannya, tetapi bagi saya ini adalah sedmasalah.

sed -ne 'p;n;n;n' <file >newfile

Jadi Anda bisa menekuknya menjadi visolusi:

:0
!Gsed -ne 'p;n;n;n'
dgc
sumber
1
+1 untuk solusi sed.
Christian Brabandt
3

Alternatif (saya kira kita mulai pada baris 1, dan menghapus baris 2-4, 6-8 dan seterusnya, sesuai contoh teks):

while line(".") < line("$")
    silent +1delete _ 3
endwhile

Jika lebih suka melakukan ini secara interaktif, Anda dapat menggunakan "register baris perintah". Yaitu, tekan

:+1del 3<CR> lalu 1000@:

Mat
sumber
1

sebuah alternatif: Anda ingin mempertahankan garis: 1, 4, dll. Anda dapat menggunakan:

awk '!((FNR-1)%3)'  file > newfile
      # awk: when a condition is given without action:
      #        prints the lines for which the condition returns 0.
      # FNR designates the line number in the current file.
      # a%3 : takes the modulus of a and 3. ( 0%3=0, 1%3=1, 2%3=2, 3%3=0, 4%3=1, etc.) 
      # This will be 0 for 3, 6, etc. 
      # But we want it to be 0 (true) for 1, 4, etc : so we substract 1 to NR

# to see that it keeps those lines:
seq 1 20 | awk '!((NR-1)%3)'
1
4
7
10
13
16
19

alternatif lain: jika Anda tahu garis yang Anda inginkan cocok dengan beberapa pola unik:

# for exemple each line you want contains "some pattern":
fgrep "some pattern" file > newfile
# (or regular grep if you want "some pattern" to be interpreted as a regexp)
Olivier Dulac
sumber