Удалить n строк пропустить 1 строку сценария

10

Я хочу создать базовый скрипт Vim, который просто удаляет n строк, пропускает 1 строку и повторяется до конца документа. Меня не интересуют конкретные совпадения, я просто хочу удалить строку. Например; Поэтому я хочу повторить команду 3ddjдля всего документа.

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.   

Так это выглядит ...

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

Спасибо.

Макс Копли
источник
Вы включили тег regular-expressionв свой вопрос, но, похоже, в вопросе не указана причина для этого с помощью регулярных выражений. Если вы действительно ищете что-то, что использует регулярные выражения, stackoverflow.com/questions/17735289/… может представлять интерес. Этот вопрос был о Notepad ++, но в ответе используется только регулярное выражение pcre. (Отказ от ответственности: я написал этот ответ.)
Джаспер
В следующий раз, когда вы зададите вопрос, не нужно писать «Спасибо за это. Отличное решение!» на каждый ответ. Это даже записывается, когда вы пытаетесь создать новый комментарий к ответу.
труба
Чтобы добавить к этому, правильный способ выразить признательность здесь - это принять ответ, который работал лучше всего для вас, и опротестовать любые ответы, которые вы считаете полезными или полезными. Люди скорее увидят это, чем комментарий «спасибо».
Слой

Ответы:

19

Очень простой подход:

  1. Перейти к первой строке, которую вы хотите удалить.
  2. Запишите макрос: qa3ddjq
  3. Повторите это с большим числом: 1000 @ a

На третьем шаге макрос будет повторяться тысячу раз или до появления ошибки. Попадание в конец файла (следовательно, нет строк для удаления) приводит к ошибке и повторение макроса отменяется.

См :help recording.

Ralf
источник
2
Это восхитительно!!!
Макс Копли
1
Пояснения: q(в командном режиме и в vim или других недавних альтернативных версиях [neovim и т. д.], но не в оригинальном vi) означает «начать запись и поместить ее в буфер« следующая буква »». следовательно: qaозначает «начать запись в буфер« a ». Затем qзаписываются все ключи, набранные после этого (до следующего в командном режиме) (вы даже можете записать: переход в режим редактирования, ввод чего-либо, выход в командный режим и т. Д.). Затем 12@aбудет повторять все действия, которые были записаны в буфере "а" 12 раз.
Оливье Дюлак
3
Кроме того, если вы не хотите запускать что-то вроде 1000@qв конце, вы можете сделать рекурсивный макрос:, qa3ddj@aq@aхотя вам, возможно, придется сделать это qaqсначала, чтобы убедиться, что все "aначинается пустым.
Джеймс
17

Самым простым решением для меня было бы:

:%norm j3dd

Это:

  • %: для каждой строки
  • norm: запустить следующие клавиши как в обычном режиме
  • j3dd: перейти на строку, а затем удалить 3 строки

Итак, с первой строки перейдите ко второй и удалите следующие 3 строки. Второй Text I want to keep.сейчас на второй линии. Спуститесь на одну строку, удалите 3. Промойте и повторите.


Примечание: если вы не хотите обрабатывать весь файл, вы можете заменить его, %normнапример, 5,$normна обработку от 5-й строки до конца файла.

Marth
источник
4
Очень хорошая альтернатива! Работает в vim (не vi). Я никогда не слышал о "норме" раньше! (а я вроде как гик)
Оливье Дюлак
6

У вас уже есть отличные решения. Вот еще один:

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

Сначала мы выполняем действие с каждой строкой ( :gсопоставление с ^(начало строки)) и для каждого номера строки выполняем результат linenumber % 4. Если результат не равен 1, мы добавляем DELETE MEв начале строки, отмечая строки, которые будут удалены следующей командой.

Следующая команда - это команда normal ( :g), которая соответствует всем строкам, которые начинаются с, DELETE MEи делает это.

Обратите внимание: вы не можете сразу удалить строку, используя первую :gкоманду, так как это приведет к изменению результирующего вычисления по модулю, и поэтому мы должны сначала пометить строки, а на втором шаге удалить их.

Кристиан Брабандт
источник
4

Я знаю, что это viканал, но для меня это sedпроблема.

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

Таким образом, вы можете превратить его в viрешение:

:0
!Gsed -ne 'p;n;n;n'
DGC
источник
1
+1 для решения sed.
Кристиан Брабандт
3

Альтернатива (я полагаю, мы начинаем со строки 1 и удаляем строки 2-4, 6-8 и т. Д., Как в тексте примера):

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

Если вы предпочитаете делать это в интерактивном режиме, вы можете использовать «регистр командной строки». То есть нажмите

:+1del 3<CR> а потом 1000@:

Matt
источник
1

альтернатива: вы хотите сохранить любые строки: 1, 4 и т. д. Вы можете использовать:

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

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

# 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)
Оливье Дюлак
источник