Auskommentieren mehrerer Codezeilen, angegeben durch Zeilennummern, mit vi oder vim

20

Ich habe aus dieser Stapelüberlauf-Frage gelernt , dass es möglich ist , einen bestimmten Bereich von Zeilennummern zu verwenden vi/ vimauszukommentieren. Angenommen, ich habe das folgende Bash-Skript:

#!/bin/bash

This
is
my
very
very
great
script

Nehmen wir nun an , dass ich Zeilennummern 6 bis 8 , um einen Kommentar wollen (was die Wörter enthalten very, veryund great) mit dem #Kommentarzeichen. In vi/ vimkann ich einfach :6,8s/^/#Folgendes eingeben:

#!/bin/bash

This
is
my
#very
#very
#great
script

die Zeilen 6 bis 8 auskommentieren.

Meine Frage ist, ist es möglich, eine ähnliche Zeile einzugeben, die das #Kommentarzeichen aus den Zeilen 6 bis 8 entfernt (aber keine anderen kommentierten Zeilen in der Datei)?

Nachdem ich das gesagt habe, stelle ich fest, dass es eine Debatte darüber gibt, ob ich tatsächlich benutze vioder vim. In der Praxis öffne ich eine Datei script.shmit dem Befehl vi script.sh. Auch wenn ich den Befehl eingebe which vi, erhalte ich /usr/bin/vi. Wenn ich jedoch einfach tippe viund drücke Enter, erhalte ich Folgendes:

~                              VIM - Vi IMproved
~
~                               version 7.2.330
~                           by Bram Moolenaar et al.
~                 Vim is open source and freely distributable
~
~                           Sponsor Vim development!
~                type  :help sponsor<Enter>    for information
~
~                type  :q<Enter>               to exit
~                type  :help<Enter>  or  <F1>  for on-line help
~                type  :help version7<Enter>   for version info

Das scheint darauf hinzudeuten, dass ich tatsächlich benutze vim. Ich greife mit SSH von meinem PC auf einen entfernten Ubuntu Linux-Cluster zu. Ich benutze kein Ubuntu Linux GUI.

Andrew
quelle

Antworten:

22

Sie können verwenden:

:6,8s/^#//

Viel einfacher ist es jedoch, den Auswahlmodus "Block Visuell" zu verwenden: Gehen Sie zum Anfang von Zeile 6, drücken Sie Ctrl-v, gehen Sie nach unten zu Zeile 8 und drücken Sie x.

Es gibt auch das Plugin "The NERD Commenter" .

Jofel
quelle
2
NERD Commenterist der Weg hierher meiner Meinung nach! +1 für das
user1146332
7

Ich weiß, dass Ihre Frage die Verwendung von vioder spezifiziert, vimaber hier sind einige andere Optionen, um dies zu tun, ohne die Datei manuell öffnen zu müssen:

  • Perl

    perl -ne 'if($. <=8 && $. >= 6){s/^\s*#//;}print' foo.sh 
    
  • Perl-Version> = 5.10

    perl -ne '$. ~~ [6..8] && s/^\s*#//;print' foo.sh 
    

    Dadurch wird der Inhalt der Datei ausgedruckt. Sie können entweder zu einer anderen ( > new_file.sh) umleiten oder idie Datei direkt bearbeiten:

    perl -i -ne '$. ~~ [6..8] && s/^\s*#//;print' foo.sh 
    
  • sed

    sed '6,8 s/^ *#//' foo.sh
    

    Verwenden Sie erneut Folgendes, um die ursprüngliche Datei zu bearbeiten i:

    sed -i '6,8 s/^ *#//' foo.sh
    
  • awk/ gawketc:

    gawk '(NR<=8 && NR>= 6){sub("^ *#","")}{print}' foo.sh
    
  • Pure bash:

    c=1; while read line; do 
      if [ $c -ge 6 ] && [ $c -le 8 ]; then 
         echo "${line/\#/}"
      else 
         echo $line 
      fi
      let c++; done < foo.sh
    
terdon
quelle
1
Es geht nicht so sehr darum, "die Datei manuell öffnen zu müssen", denn normalerweise entscheidest du, welche Zeilen bei der visuellen Überprüfung während der Bearbeitung kommentiert werden sollen :) Aber sicher, es ist eine gute Antwort für die Vollständigkeit.
Paulo Almeida
2
@PauloAlmeida du hast natürlich recht. Ich dachte nur, dass es nützlich sein könnte, da das OP die Zeilennummern bereits kennt (aufgrund des ersten zum Kommentieren verwendeten Befehls) und die von mir gezeigten Tools auf jeden Fall auf eine Vielzahl von Problemen angewendet werden können.
Terdon
4

viist ein symbolischer Link zu den vimmeisten GNU / Linux-Distributionen. Sie verwenden ihn also tatsächlich, vimwenn Sie tippen vi.

Um die Kommentare zu entfernen, können Sie Folgendes eingeben: :6,8s/^#//oder ein :6,8s/^\s*#//vorangestelltes Leerzeichen vor dem # Symbol entfernen .

lgeorget
quelle
1
Vielen Dank. Es scheint, dass es Tippfehler geben kann. Vielleicht sollte es sein :6,8s/^#//und 6,8s/^\s*#//?
Andrew
3

Sie verwenden wahrscheinlich vim.tiny. In jedem Fall können Sie die ersten Kommentare entfernen mit:

:6,8s/^#//

Wenn Sie sie auf eine andere Weise einfügen (z. B. mit einem zusätzlichen Leerzeichen), müssen Sie möglicherweise alle anderen Elemente entfernen. Mit full vim ist es einfacher, Spalten visuell auszuwählen und Zeichen einzufügen / zu löschen, um dasselbe zu tun.

Paulo Almeida
quelle
3

Persönlich benutze ich am liebsten den visuellen Block-Modus

ctrl+ vUm in den visuellen Blockmodus zu gelangen, wählen Sie mit den Pfeiltasten oder hjkl die Zeilen aus und drücken Sie xoder del.

Willst du sie zurück?

ctrl+ vTreffen Sie die Auswahl, dann I(Großbuchstaben i)#Esc

exussum
quelle
3

AFAIK, vi ist heutzutage normalerweise ein Symlink von vim (versuchen Sie which vioder type viund folgen Sie dann den Symlinks). Vielleicht sogar /usr/bin/vi-> /etc/alternatives/vi-> /usr/bin/vim.basic.

Um mehrere Kommentarzeilen zu entfernen, bevorzuge ich es, einen vertikalen Block über auszuwählen CtrlVund zu löschen. Wenn Sie einen Kommentar Symbol auf mehrere Zeilen hinzufügen müssen, könnten Sie CtrlV, dann ShiftIgeben #und Esc, und ein Kommentar auf mehrere Zeilen hinzugefügt werden.

Boris Burkov
quelle
2

Die obigen Antworten verwenden

:6,8s/^#//

sind perfekte Lösung, aber etwas umständlich zu tippen. Dies kann vereinfacht werden, indem neue Befehle in definiert werden ~/.vimrc.

command -range=% C :<line1>,<line2>s/^/#/
command -range=% D :<line1>,<line2>s/^#//

Und Sie können einfach tippen

:6,8C
:6,8D

Befehl platzieren / löschen.

Wenn Sie den visuellen Modus mögen, können Sie Karten definieren

map <F7> :s/^/#/<CR>
map <F8> :s/^#//<CR>

Damit müssen Sie nur einen Linienbereich im visuellen Modus auswählen F7und F8auf und drücken , um Kommentare einzufügen bzw. zu entfernen.

Bernhard
quelle
1

Diese Antwort ist hier auf 1) den richtigen Code zeigen , in eine Paste .vimrczu erhalten vim 7.4+Block zu tun zu kommentieren / uncommenting während Einrückungsebene mit 1 Verknüpfung im visuellen Modus zu halten und 2) es zu erklären.

Hier ist der Code:

let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.[ch]    let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.cpp    let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.py    let b:commentChar='#'
autocmd BufNewFile,BufReadPost *.*sh    let b:commentChar='#'
function! Docomment ()
  "make comments on all the lines we've grabbed
  execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e'
endfunction
function! Uncomment ()
  "uncomment on all our lines
  execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e'
endfunction
function! Comment ()
  "does the first line begin with a comment?
  let l:line=getpos("'<")[1]
  "if there's a match
  if match(getline(l:line), '^\s*'.b:commentChar)>-1
    call Uncomment()
  else
    call Docomment()
  endif
endfunction
vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>

Wie es funktioniert:

  • let b:commentChar='//': Dies erstellt eine Variable in vim. Das bhier bezieht sich auf den Gültigkeitsbereich, der in diesem Fall im Puffer enthalten ist, dh die aktuell geöffnete Datei. Ihre Kommentarzeichen sind Zeichenfolgen und müssen in Anführungszeichen gesetzt werden. Die Anführungszeichen sind nicht Teil dessen, was beim Umschalten von Kommentaren ersetzt wird.

  • autocmd BufNewFile,BufReadPost *...: Autocommands lösen verschiedene Dinge aus. In diesem Fall werden diese ausgelöst, wenn eine neue Datei oder die gelesene Datei mit einer bestimmten Erweiterung endet. Nach dem Auslösen führen Sie den folgenden Befehl aus, mit dem Sie den commentCharDateityp ändern können. Es gibt andere Möglichkeiten, dies zu tun, aber sie sind für Anfänger (wie mich) verwirrender.

  • function! Docomment(): Funktionen werden durch Beginnen mit functionund Beenden mit deklariert endfunction. Funktionen müssen mit einem Großbuchstaben beginnen. das !gewährleistet , dass diese Funktion alle vorherigen Funktionen überschreibt definiert als Docomment()mit dieser Version von Docomment(). Ohne !hatte ich Fehler, aber das könnte daran liegen, dass ich neue Funktionen über die vim-Befehlszeile definierte.

  • execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e': Execute ruft einen Befehl auf. In diesem Fall wird ausgeführt substitute, was einen Bereich annehmen kann (standardmäßig ist dies die aktuelle Zeile), z. B. %für den gesamten Puffer oder '<,'>für den hervorgehobenen Abschnitt. ^\s*ist regulär, um mit dem Anfang einer Zeile übereinzustimmen, gefolgt von einer beliebigen Anzahl von Leerzeichen, die dann (aufgrund von &) angehängt werden . Das .hier wird für die Verkettung von Zeichenfolgen verwendet, da escape()es nicht in Anführungszeichen eingeschlossen werden kann. escape()Ermöglicht es Ihnen, Zeichen commentChar, die mit den Argumenten übereinstimmen (in diesem Fall \und /), zu maskieren, indem Sie ihnen ein voranstellen \. Danach verketten wir wieder mit dem Ende unserer substituteZeichenkette, die das hateFlagge. Dieses Flag lässt uns stillschweigend scheitern, was bedeutet, dass wir nicht darüber schreien, wenn wir in einer bestimmten Zeile keine Übereinstimmung finden. Insgesamt können Sie in dieser Zeile ein Kommentarzeichen gefolgt von einem Leerzeichen vor dem ersten Text einfügen, um die Einrückungsstufe beizubehalten.

  • execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e': Dies ist ähnlich wie bei unserem letzten großen langen Befehl. Einzigartig an diesem haben wir \v, der sicherstellt, dass wir uns nicht entziehen müssen (), und 1der sich auf die Gruppe bezieht, die wir mit unserem gemacht haben (). Grundsätzlich stimmen wir mit einer Zeile überein, die mit einer beliebigen Anzahl von Leerzeichen beginnt, gefolgt von unserem Kommentarzeichen und einer beliebigen Anzahl von Leerzeichen. Wir behalten nur den ersten Satz von Leerzeichen bei. eLassen Sie uns erneut unbemerkt scheitern, wenn in dieser Zeile kein Kommentarzeichen steht.

  • let l:line=getpos("'<")[1]: dies setzt eine Variable, ähnlich wie wir es mit unserem Kommentarzeichen gemacht haben, lbezieht sich jedoch auf den lokalen Gültigkeitsbereich (lokal für diese Funktion). getpos()Ruft die Position des Beginns unserer Hervorhebung ab und [1]bedeutet, dass wir uns nur um die Zeilennummer kümmern, nicht um andere Dinge wie die Spaltennummer.

  • if match(getline(l:line), '^\s*'.b:commentChar)>-1: Sie wissen, wie es iffunktioniert. match()prüft, ob das Erste das Zweite enthält, also greifen wir zu der Zeile, in der wir mit der Hervorhebung begonnen haben, und prüfen, ob sie mit einem Leerzeichen beginnt, gefolgt von unserem Kommentarzeichen. match()Gibt den Index zurück, in dem dies zutrifft und -1wenn keine Übereinstimmungen gefunden wurden. Da ifalle Zahlen ungleich Null als wahr ausgewertet werden, müssen wir unsere Ausgabe vergleichen, um festzustellen, ob sie größer als -1 ist. Der Vergleich in vimgibt 0 zurück, wenn er falsch ist, und 1, wenn er ifrichtig ist.

  • vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>: vnoremapbedeutet, den folgenden Befehl im visuellen Modus abzubilden, aber nicht rekursiv abzubilden (dh keine anderen Befehle zu ändern, die auf andere Weise verwendet werden könnten). Grundsätzlich sollten Sie als Anfänger immer noremapdarauf achten, dass Sie nichts kaputt machen. <silent>bedeutet "Ich will nicht deine Worte, nur deine Taten" und weist es an, nichts in die Befehlszeile zu drucken. <C-r>ist das, was wir mappen, was in diesem Fall Strg + R ist (beachten Sie, dass Sie mit diesem Mapping Cr im normalen Modus immer noch normal für "Wiederherstellen" verwenden können). C-uDas ist ein bisschen verwirrend, aber im Grunde stellt es sicher, dass Sie Ihre visuelle Hervorhebung nicht aus den Augen verlieren (laut dieser Antwort startet Ihr Befehl mit '<,'>dem, was wir wollen).callHier wird vim lediglich angewiesen, die von uns benannte Funktion auszuführen, und es wird <cr>auf das Drücken der enterSchaltfläche verwiesen. Wir müssen es einmal drücken, um die Funktion tatsächlich aufzurufen (ansonsten haben wir nur call function()die Befehlszeile eingegeben , und wir müssen es erneut drücken, damit unsere Stellvertreter den ganzen Weg durchlaufen (nicht wirklich sicher, warum, aber was auch immer).

Wie auch immer, hoffentlich hilft das. Dies nimmt alles mit v, Voder C-vüberprüft, ob die erste Zeile kommentiert ist. Wenn ja, kommentieren Sie alle markierten Zeilen aus und fügen Sie, falls nicht, jeder Zeile eine zusätzliche Ebene mit Kommentarzeichen hinzu. Das ist mein gewünschtes Verhalten; Ich wollte nicht nur, dass es umschaltet, ob jede Zeile im Block kommentiert wurde oder nicht, deshalb funktioniert es perfekt für mich, nachdem ich mehrere Fragen zu diesem Thema gestellt habe.

jeremysprofile
quelle
0

Dort wird dieses lebensverändernde Plugin tpopegenanntvim-commentary

https://github.com/tpope/vim-commentary

Dieses Plugin bietet :

  • Geistige Gesundheit
  • Richtig eingerückte Kommentare
  • Kommentiert keine leeren / unnötigen Zeilen aus

Verwendung :

  • Installation über Vundle (oder Pathogen, denke ich).
  • Markieren Sie Ihren Text und drücken Sie, :welcher als angezeigt wird:<,'>
  • Geben Sie Commentary hier ein :<,'>Commentaryund drücken Sie die Eingabetaste.
  • Bom. Deine erledigte Knospe.
Weston Ganger
quelle