Закомментирование нескольких строк кода, заданных номерами строк, с использованием vi или vim

20

Из этого вопроса переполнения стека я узнал, что можно использовать vi/ vimдля закомментирования указанного диапазона номеров строк. Например, предположим, у меня есть следующий скрипт bash:

#!/bin/bash

This
is
my
very
very
great
script

Теперь предположим , что я хочу , чтобы закомментировать номера строк 6 по 8 (которые содержат слова very, veryи great) , используя #символ комментария. В vi/ vimя могу просто напечатать, :6,8s/^/#чтобы получить следующее:

#!/bin/bash

This
is
my
#very
#very
#great
script

который комментирует строки с 6 по 8.

Мой вопрос, можно ли ввести подобный один вкладыш , который будет удалять на #символ комментария из строки 6 до 8 (но не каких - либо других комментировал строк в файле)?

Сказав это, я понимаю, что есть некоторые споры о том, использую ли я на самом деле viили vim. На практике я открываю файл script.shс помощью команды vi script.sh. Также, когда я набираю команду which vi, я получаю /usr/bin/vi. Тем не менее, когда я просто печатаю viи нажимаю Enter, я получаю это:

~                              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

который, кажется, предполагает, что я на самом деле использую vim. Я получаю доступ к удаленному кластеру Ubuntu Linux, используя SSH с моего компьютера. Я не использую графический интерфейс Ubuntu Linux.

Эндрю
источник

Ответы:

22

Вы можете использовать:

:6,8s/^#//

Но гораздо проще использовать режим выбора Block Visual: перейдите к началу строки 6, нажмите Ctrl-v, перейдите к строке 8 и нажмите x.

Существует также плагин "NERD Commenter" .

jofel
источник
2
NERD Commenterэто путь сюда, по моему мнению! +1 за это
user1146332
7

Я знаю, что ваш вопрос определяет использование viили, vimно вот несколько других вариантов сделать это без необходимости открывать файл вручную:

  • Perl

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

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

    Это распечатает содержимое файла, вы можете либо перенаправить на другой ( > new_file.sh), либо использовать iдля редактирования файла на месте:

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

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

    Опять же, чтобы сделать это редактировать оригинальный файл на месте, используйте i:

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

    gawk '(NR<=8 && NR>= 6){sub("^ *#","")}{print}' foo.sh
    
  • Чистый 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
    
Тердон
источник
1
Это не столько вопрос «необходимости вручную открывать файл», потому что обычно вы решаете, какие строки комментировать при визуальном осмотре при редактировании :) Но, конечно, это хороший ответ для полноты.
Пауло Алмейда
2
@PauloAlmeida ты прав конечно. Я просто подумал, что это может быть полезно, так как OP уже знает номера строк (из-за первой команды, использованной для их комментирования), и, в любом случае, инструменты, которые я показываю, могут быть применены к различным проблемам.
Terdon
4

viявляется символической ссылкой vimв большинстве дистрибутивов GNU / Linux, так что вы действительно используете vimпри вводе vi.

Чтобы удалить комментарии, вы можете ввести: :6,8s/^#//или :6,8s/^\s*#//отбросить пробел перед # символом.

lgeorget
источник
1
Спасибо. Кажется, что могут быть опечатки. Может быть так :6,8s/^#//и должно быть 6,8s/^\s*#//?
Андрей
3

Вы, вероятно, используете vim.tiny. В любом случае вы можете удалить начальные комментарии с помощью:

:6,8s/^#//

Конечно, если вы вставляете их другим способом (например, с дополнительным пробелом), вам может потребоваться удалить все остальное. С полной версией визуальный выбор столбцов и вставка / удаление символов - более простой способ сделать то же самое.

Пауло Алмейда
источник
3

Лично мой любимый способ - использовать режим визуального блока.

ctrl+, vчтобы войти в режим визуального блока, используйте клавиши со стрелками или hjkl для выбора линий и нажмите xили del.

Хотите их вернуть?

ctrl+ vсделать выбор, затем I(заглавная я)#Esc

exussum
источник
3

AFAIK, vi обычно является символической ссылкой vim в настоящее время (попробуйте which viили type viзатем перейдите по символическим ссылкам). Может быть, даже /usr/bin/vi-> /etc/alternatives/vi-> /usr/bin/vim.basic.

Лично, чтобы удалить несколько строк комментариев, я предпочитаю выделять вертикальный блок CtrlVи удалять его. Если вам нужно добавить символ комментария к нескольким строкам, вы можете CtrlVзатем ShiftIввести #и Esc, и комментарий будет добавлен к нескольким строкам.

Борис Бурков
источник
2

Ответы выше, используя

:6,8s/^#//

являются идеальным решением, но немного громоздким для ввода. Это можно упростить, определив новые команды в~/.vimrc .

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

И вы можете просто напечатать

:6,8C
:6,8D

разместить / удалить команду.

Если вам нравится визуальный режим, вы можете определить карты

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

Так что вам нужно только выбрать диапазон строк в визуальном режиме, а затем нажать F7и, F8чтобы добавить и удалить комментарии соответственно.

Бернхард
источник
1

Существует изменения плагина, эта жизнь tpopeназываетсяvim-commentary

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

Этот плагин обеспечивает :

  • вменяемость
  • Правильно отступленные комментарии
  • Не комментирует пустые / ненужные строки

Использование :

  • Установить через Vundle (или, я думаю, Pathogen).
  • Выделите ваш текст и нажмите, :который будет отображаться как:<,'>
  • Введите Комментарий здесь :<,'>Commentaryи нажмите Enter.
  • Bom. Твой готовый бутон.
Уэстон Гангер
источник
1

Этот ответ здесь 1) показать правильный код, чтобы вставить в, .vimrcчтобы получитьvim 7.4+ возможность комментировать / раскомментировать блок, сохраняя уровень отступа с 1 ярлыком в визуальном режиме и 2), чтобы объяснить это.

Вот код:

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>

Как это работает:

  • let b:commentChar='//': Это создает переменную в vim. bздесь относится к области, которая в данном случае содержится в буфер, то есть открытый в данный момент файл. Ваши символы комментариев являются строками и должны быть заключены в кавычки, кавычки не являются частью того, что будет подставлено при переключении комментариев.

  • autocmd BufNewFile,BufReadPost *...: Автокоманды запускаются для разных вещей, в этом случае они запускаются, когда новый файл или прочитанный файл заканчивается с определенным расширением. После запуска выполните следующую команду, которая позволяет нам изменять commentCharзависимости в зависимости от типа файла. Есть и другие способы сделать это, но они больше сбивают с толку новичков (таких как я).

  • function! Docomment(): Функции объявляются, начиная с functionи заканчивая endfunction. Функции должны начинаться с заглавной буквы. что !гарантирует , что эта функция переопределяет все предыдущие функции , определенные как Docomment()с этой версией Docomment(). Без этого у !меня были ошибки, но это могло быть потому, что я определял новые функции через командную строку vim.

  • execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e': Выполнить вызывает команду. В этом случае мы выполняем substitute, который может принимать диапазон (по умолчанию это текущая строка), например, %для всего буфера или '<,'>для выделенного раздела. ^\s*является регулярным выражением, чтобы соответствовать началу строки, за которой следует любое количество пробелов, которые затем добавляются (из-за &). .Здесь используется для конкатенации, так как escape()не может быть завернуты в кавычки. escape()позволяет вам экранировать символ, commentCharкоторый соответствует аргументам (в данном случае \и /), добавляя их с помощью \. После этого мы соединяем снова с концом нашегоsubstitute строки, который имеетeфлаг. Этот флаг позволяет нам молча потерпеть неудачу, что означает, что если мы не найдем совпадения в данной строке, мы не будем кричать об этом. В целом, эта строка позволяет поставить символ комментария, за которым следует пробел перед первым текстом, что означает, что мы сохраняем наш уровень отступа.

  • execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e'Это похоже на нашу последнюю огромную длинную команду. У нас есть уникальная возможность \v, которая гарантирует, что нам не нужно избегать наших (), и 1которая относится к группе, которую мы создали с нашей (). По сути, мы сопоставляем строку, начинающуюся с любого количества пробелов, а затем наш символ комментария, за которым следует любое количество пробелов, и мы сохраняем только первый набор пробелов. Опять же, eдавайте молча потерпим неудачу, если у нас нет символа комментария в этой строке.

  • let l:line=getpos("'<")[1]: это устанавливает переменную так же, как мы сделали с нашим символом комментария, но lссылается на локальную область видимости (локальную для этой функции). getpos()получает позицию, в данном случае, начала нашего выделения, и [1]означает, что мы заботимся только о номере строки, а не о других вещах, таких как номер столбца.

  • if match(getline(l:line), '^\s*'.b:commentChar)>-1Знаете, как ifработает. match()проверяет, содержит ли первая вещь вторую, поэтому мы берем строку, с которой мы начали выделение, и проверяем, начинается ли она с пробела, за которым следует символ комментария. match()возвращает индекс, где это правда, и -1если совпадений не найдено. Так как ifвсе ненулевые числа оцениваются как истинные, мы должны сравнить наш вывод, чтобы увидеть, больше ли он -1. Сравнение в vimвозвращает 0, если ложь, и 1, если истина, что и ifнужно видеть, чтобы оценить правильно.

  • vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>: vnoremapозначает отображать следующую команду в визуальном режиме, но не отображать ее рекурсивно (то есть не изменять никакие другие команды, которые могут использоваться другими способами). По сути, если вы новичок Vim, всегда используйте, noremapчтобы убедиться, что вы не сломать вещи. <silent>означает «Я не хочу ваших слов, только ваши действия» и говорит, что ничего не печатать в командной строке. <C-r>это то, что мы отображаем, в данном случае это ctrl + r (обратите внимание, что вы все равно можете использовать Cr обычно для «повторения» в обычном режиме с этим отображением). C-uэто немного сбивает с толку, но в основном это гарантирует, что вы не потеряете свою визуальную подсветку (в соответствии с этим ответом ваша команда начинает с '<,'>чего мы и хотим).call здесь просто говорит vim выполнить функцию, которую мы назвали, и<cr> ссылается на enterнажатие кнопки. Мы должны нажать ее один раз, чтобы фактически вызвать функцию (в противном случае мы просто набрали ее call function()в командной строке, и нам нужно нажать ее снова, чтобы наши заменители прошли весь путь (не совсем понятно, почему, но как угодно).

В любом случае, надеюсь, это поможет. Это будет принимать что - либо подсвечены v, Vили C-v, проверить , если первая строка комментариев, если да, попробуйте раскомментировать все выделенные строки, а если нет, добавить дополнительный слой символы комментария к каждой строке. Это мое желаемое поведение; Я не просто хотел, чтобы он переключался независимо от того, была ли прокомментирована каждая строка в блоке или нет, поэтому он отлично работает после того, как я задал несколько вопросов на эту тему.

jeremysprofile
источник