N Zeilen löschen 1-Zeilen-Skript überspringen

10

Ich möchte ein einfaches Vim-Skript erstellen, das einfach n Zeilen löscht, 1 Zeile überspringt und bis zum Ende des Dokuments wiederholt. Ich kümmere mich nicht um bestimmte Übereinstimmungen, ich möchte nur die Zeile löschen. Zum Beispiel; Daher möchte ich den Befehl 3ddjfür das gesamte Dokument wiederholen .

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.   

So sieht es aus wie ...

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

Vielen Dank.

Max Copley
quelle
Sie haben das Tag regular-expressionin Ihre Frage aufgenommen, aber die Frage scheint keinen Grund anzugeben, dies mit regulären Ausdrücken zu tun. Wenn Sie tatsächlich nach etwas suchen, das reguläre Ausdrücke verwendet, kann stackoverflow.com/questions/17735289/… von Interesse sein. Diese Frage betraf Notepad ++, aber die Antwort verwendet nur einen PCE-Regex. (Haftungsausschluss: Ich habe diese Antwort geschrieben.)
Jasper
Wenn Sie das nächste Mal eine Frage stellen, müssen Sie nicht schreiben: "Danke dafür. Großartige Lösung!" auf jede einzelne Antwort. Dies wird sogar ausgeschrieben, wenn Sie versuchen, einen neuen Kommentar zu einer Antwort zu erstellen.
Pipe
Um das noch zu ergänzen, besteht der richtige Weg, hier Wertschätzung zu zeigen, darin, die Antwort zu akzeptieren, die für Sie am besten funktioniert hat, und alle Antworten zu bewerten, die Sie für hilfreich oder nützlich halten. Die Leute würden das viel lieber sehen als einen "Dank" -Kommentar.
B-Schicht

Antworten:

19

Sehr einfacher Ansatz:

  1. Gehen Sie zur ersten Zeile, die Sie löschen möchten.
  2. Zeichnen Sie ein Makro auf: qa3ddjq
  3. Wiederholen Sie dies mit einer hohen Zahl: 1000 @ a

Schritt drei wiederholt das Makro tausendmal oder bis ein Fehler auftritt. Wenn Sie das Dateiende treffen (daher keine zu löschenden Zeilen), wird ein Fehler ausgegeben und die Wiederholung des Makros wird abgebrochen.

Siehe :help recording.

Ralf
quelle
2
Das ist erstaunlich!!! Vielen Dank, das hat bei mir funktioniert: D
Max Copley
1
Erläuterungen: q(im Befehlsmodus und in vim oder anderen neueren alternativen Versionen [neovim usw.], jedoch nicht im Original vi) bedeutet "Aufnahme starten und in den Puffer" Nächster Buchstabe "legen". daher: qabedeutet "Aufnahme in den 'a'-Puffer starten". Anschließend werden alle danach eingegebenen Tasten (bis zur nächsten qim Befehlsmodus) aufgezeichnet (Sie können sogar aufzeichnen: in den Bearbeitungsmodus wechseln, etwas eingeben, in den Befehlsmodus wechseln usw.). Dann 12@awürden alle Aktionen, die im Puffer "a" aufgezeichnet wurden, 12 Mal wiederholt.
Olivier Dulac
3
Wenn Sie nicht so etwas wie 1000@qam Ende ausführen möchten , können Sie außerdem ein rekursives Makro erstellen: qa3ddj@aq@aDies müssen Sie jedoch möglicherweise qaqzuerst tun , um sicherzustellen, dass der "aStart leer ist.
James
17

Die einfachste Lösung für mich wäre:

:%norm j3dd

Das ist:

  • %: für jede Zeile
  • norm: Führen Sie die folgenden Tasten wie im normalen Modus aus
  • j3dd: gehe in die Zeile und lösche 3 Zeilen

Gehen Sie also von der ersten Zeile zur zweiten und löschen Sie die nächsten 3 Zeilen. Die zweite Text I want to keep.befindet sich jetzt in der zweiten Zeile. Gehen Sie eine Zeile nach unten, löschen Sie 3. Spülen und wiederholen.


Hinweis: Wenn Sie nicht die gesamte Datei verarbeiten möchten, können Sie die %normdurch z. B. ersetzen 5,$norm, um von der 5. Zeile bis zum Ende der Datei zu verarbeiten.

Marth
quelle
4
Sehr schöne Alternative! Funktioniert in vim (nicht vi). Ich habe noch nie von "Norm" gehört! (und ich bin eine Art vi [m] Geek)
Olivier Dulac
6

Sie haben bereits einige großartige Lösungen zur Verfügung. Hier ist noch einer:

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

Zuerst führen wir eine Aktion für jede Zeile aus ( :gÜbereinstimmung mit dem ^(Zeilenanfang)) und führen für jede Zeilennummer das Ergebnis von aus linenumber % 4. Wenn das Ergebnis ungleich ist 1, fügen wir DELETE MEam Anfang der Zeile hinzu und markieren die Zeilen, die mit dem nächsten Befehl gelöscht werden sollen.

Der nächste Befehl ist ein regulärer ( :g) Befehl, der allen Zeilen entspricht, die mit beginnen, DELETE MEund dies tut.

Hinweis: Sie können die Zeile nicht sofort mit dem ersten :gBefehl löschen , da dies die resultierende Modulo-Berechnung ändern würde. Daher müssen wir die Zeilen zuerst markieren und in einem zweiten Schritt löschen.

Christian Brabandt
quelle
4

Ich weiß, dass dies der viKanal ist, aber für mich ist das ein sedProblem.

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

So können Sie es in eine viLösung verwandeln :

:0
!Gsed -ne 'p;n;n;n'
dgc
quelle
1
+1 für eine sed-Lösung.
Christian Brabandt
3

Eine Alternative (ich nehme an, wir beginnen in Zeile 1 und löschen die Zeilen 2-4, 6-8 usw. gemäß einem Beispieltext):

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

Wenn Sie dies lieber interaktiv tun möchten, können Sie das "Befehlszeilenregister" verwenden. Das heißt, drücken Sie

:+1del 3<CR> und dann 1000@:

Matt
quelle
1

eine Alternative: Sie möchten alle Zeilen behalten: 1, 4 usw. Sie könnten verwenden:

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

Eine andere Alternative: Wenn Sie wissen, dass die gewünschten Linien mit einem eindeutigen Muster übereinstimmen:

# 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
quelle