Vim: как удалить каждую вторую строку?


Ответы:


105

Для этого можно использовать макрос. Сделайте следующее.

  • Запуск в командном режиме.
  • Перейти к началу файла, нажав gg.
  • Нажмите qq.
  • Щелкните стрелку вниз и нажмите ddпосле.
  • Нажмите q.
  • Нажмите 10000@q

PS: Чтобы перейти в командный режим, просто нажмите Escape пару раз.


11
Если, конечно, ваш файл содержит менее 20 000 строк :-)
paxdiablo

3
На самом деле ты ошибаешься, Майкл. Это работает безупречно, поскольку VI прекратит запуск макроса, как только достигнет конца файла. Вы можете легко попробовать это на примере выше.
rui

1
Ну, как и любой макрос, вам нужно сделать это правильно с первого раза, но после этого вы можете применить к любому файлу, просто набрав 10000 @ q. В любом случае, я считаю, что это всего лишь вопрос вкусов, поэтому я решительно не собираюсь начинать философские дебаты. :)
rui

3
Я предпочитаю использовать «макрос». Используя макрос, вы «описываете», как вы решите одну конкретную задачу, и позволяете VIM повторять ее за вас. RUI, я бы предпочел использовать j вместо клавиши со стрелкой.
SolutionYogi

4
:g/^/+dот пользователя stackoverflow.com/users/254635/ib (ниже) - более элегантный способ решить эту проблему.
SergioAraujo 01

256

Элегантный (и эффективный) способ выполнить задачу - вызвать :+deleteкоманду, удаляющую строку, следующую за текущей, в каждой строке с помощью :globalкоманды:

:g/^/+d

10
Почему этот ответ не получил больше голосов? Это так чисто и просто. В качестве альтернативы вы можете удалить первую строку и выполнить указанную выше команду, чтобы удалить все нечетные строки.
Usagi

3
@Usagi: Спасибо! Я так же отношусь к этому. И да, вы абсолютно правы, :1d|g/^/+dудаляет лишние строчки.
ib.

@Usagi Другой ответ был выбран как «лучший ответ» за 2 года до его появления. Кроме того, хотя это более элегантное решение, его можно было бы написать более полезным способом (т. Е. Нет упоминания о том, что делает ^, а макрос прост для понимания).
user1271772

3
Извините, но без объяснения того, как эта команда выполняет желаемое поведение, я бы не проголосовал за нее, а вместо этого предпочел бы принятый ответ, так как я понимаю, как он достигает цели. В этом разница между тем, чтобы дать мужчине рыбу и научить его ловить рыбу.
Гейб

3
Я не знаю, этот ответ заставил меня пойти и научиться ловить рыбу с помощью команды: g (то есть заставило меня погуглить эту страницу - vim.wikia.com/wiki/Power_of_g ).
Snetch

67

Мы можем использовать :normalили :normдля выполнения заданных команд нормального режима. Источник.

:%norm jdd

15
Этому ответу не уделяется достаточно внимания, возможно, из-за отсутствия объяснения здесь и в связанной, грязной шпаргалке. команда norm запускает команды нормального режима, эквивалентные буквам, которые следуют за ней. Итак, здесь выполняется j для перемещения вниз по строке и dd для ее удаления. Это можно обобщить до X-й строки, добавив в этом случае больше 'j'.
imoatama

5
а% - это сокращение для 1, $ (выполните следующую команду со строки 1 до конца)
Ламбарт,

3
Меня интересует, почему %norm ddjне работает, если вы хотите удалить нечетные строки.
Cyker

10
:map ^o ddj^o
^o

Здесь ^ обозначает CTRL. Рекурсивный макрос для удаления строки каждые две строки. Хорошо выберите первую строчку, и готово.


8

из почтового архива vim :

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

(При вводе в одной строке командной строки vim удаляются строки 1,3,5,7, ...)


4
Тогда я бы предпочел !perl -ne 'print unless $. % 2':-)
Alex Brasetvik

И, Алекс, я определенно предпочитаю свое решение твоему, но это стоит рассмотреть, поскольку это единственное разумное решение, использующее здесь только сам vim.
Михаил Крелин - хакер

Макро-путь намного проще.
trusktr

+1 из-за гибкости, с if (expression)которой также работает для каждой третьей строки и т. Д.
Йенс

5

Вы всегда можете передать команду оболочки, что означает, что вы можете использовать любой язык сценариев, который вам нравится:

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

(или используйте «если» вместо «если», в зависимости от того, какие строки вы хотите)


Вам не нужен -lпереход на Perl ... также, я бы сказал, что awkон немного более распространен, чем Perl, хотя на самом деле в наши дни он не намного больше и может сделать это короче: :%!awk NR\%2или :%!awk 1-NR\%2для других строк.
ephemient

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

альтернативно

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

в зависимости от того, какую половину вы хотите отсеять.


Эмм, почему бы не использовать существующую NRпеременную?
ephemient

Правильно. Потому что я забыл об этом. ;-) Но на самом деле «правильный» вариант с NR будет еще длиннее. И не было бы двух симпатичных аналогов.
Михаил Крелин - хакер

:%!awk NR\%2или :%!awk 1-NR\%2, как я написал в другом комментарии. Это вряд ли дольше.
ephemient

1
1-NRдлиннее чем c++. Да, я знаю, что это один персонаж. Как я уже сказал, настоящая причина в том, что я забыл об этом. Во всяком случае, похоже, что люди не ценят здесь красоты awk.
Михаил Крелин - хакер

И NRкороче ++c:)
ephemient

3

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

:.,/fff/s/\n.*\(\n.*\)/\1/g
  • Это .,/fff/диапазон для замены. Это означает «от этой строки до строки, соответствующей регулярному выражению fff(в данном случае последней строки).
  • s///это замещающая команда. Он ищет регулярное выражение и заменяет каждое его вхождение строкой. Знак gв конце означает повторение подстановки до тех пор, пока регулярное выражение будет найдено.
  • Регулярное выражение \n.*\(\n.*\)соответствует новой строке, затем целой строке ( .*соответствует любому количеству символов, кроме новой строки), затем еще одной новой строке и другой строке. Скобки \(и \)вызывают запись выражения внутри них, чтобы мы могли использовать его позже, используя \1.
  • \1 вставляет сгруппированную новую строку и строку после нее обратно, потому что мы не хотим, чтобы следующая строка тоже уходила - мы просто хотим, чтобы механизм подстановки прошел мимо нее, чтобы мы не удаляли ее при следующей замене.

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


Или $вместо /fff/, для конца файла, независимо от содержимого файла.
ephemient

3

В качестве другого подхода вы также можете использовать python, если ваш vim поддерживает его.

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

b = cb[:]временно копирует все строки в текущем буфере в b. b[::2]получает каждую вторую строку из буфера и назначает ее всему текущему буферу cb[:]. Копирование в bнеобходимо, поскольку буферные объекты, похоже, не поддерживают расширенный синтаксис среза.

Вероятно, это не «путь vim», но его будет легче запомнить, если вы знаете 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

решение

вы можете попробовать это в vim

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

редактировать

Постараюсь пояснить (две части)

первая часть диапазон выбора ( :from,to)
вторая часть действие ( dудалить)

  • диапазон, если от первой до предпоследней строки (:1,$-1 )
  • globaly ( g) delete ( +1d) следующая строка

вы можете попробовать перейти к первой строке вашего файла и выполнить, :+1dвы увидите, что следующая строка исчезнет

Я знаю, что это грязно, но это энергично и работает


Ясно, как грязь. Спасибо!
Генри Хенринсон,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.