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

254

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

:g/^/+d

10
Чому ця відповідь не отримала більше голосів? Це так чисто і просто. Крім того, ви можете видалити перший рядок і виконати наведену вище команду, щоб видалити всі непарні рядки.
Усагі

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
Ця відповідь не привертає достатньої уваги, можливо, через відсутність пояснень як тут, так і на пов'язаному, брудному шпаргалці. команда норма виконує команди нормального режиму, еквівалентні буквам, що слідують за нею. Отже, тут працює j, щоб рухатись по рядку вниз, а dd, щоб видалити його. Це можна узагальнити до X-го рядка, додавши в цьому випадку більше 'j'.
imoatama

5
і% є скороченим для 1, $ (виконайте наступну команду з рядка 1 до кінця)
Ламбарт,

3
Мене цікавить, чому %norm ddjне працює, якщо ви хочете видалити непарні рядки.
Байкер

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':-)
Алекс Брасетвік

І, Алекс, я б напевно віддав перевагу своєму рішенню, а не твоєму, але це варто розглянути, оскільки це єдине розумне рішення, яке використовує тут лише vim.
Майкл Крелін - хакер

Макро шлях набагато простіший.
trusktr

+1 через гнучкість, if (expression)яка також працює для кожного третього рядка і т. Д.
Йенс

5

Ви завжди можете скопіювати команду оболонки, що означає, що ви можете використовувати будь-яку мову сценаріїв, яка вам подобається:

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

(або використовуйте "якщо" замість "якщо", залежно від того, які рядки ви хочете)


Вам не потрібен -lперехід на Perl ... також, я б сказав, що awkце трохи ширше, ніж Perl, хоча насправді це не так вже й багато в наші дні, і це можна зробити коротше:, :%!awk NR\%2або :%!awk 1-NR\%2для інших рядків.
ефемієнт

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

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

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

залежно від того, яку половину ви хочете відсіяти.


Чому б не використати існуючу NRзмінну?
ефемієнт

Правильно. Бо я про це забув. ;-) Але насправді, "правильний" варіант буде ще довшим із NR. І не було б двох приємних на вигляд аналогів.
Майкл Крелін - хакер

:%!awk NR\%2або :%!awk 1-NR\%2, як я писав в іншому коментарі. Це навряд чи довше.
ефемієнт

1
1-NRдовше ніж c++. Так, я знаю, що це один персонаж. Як я вже сказав - справжня причина в тому, що я про це забув. У будь-якому випадку, схоже, люди тут не цінують красу awk.
Майкл Крелін - хакер

І NR коротший ніж ++c:)
ефемієнт

3

Ви можете використовувати власні можливості пошуку та заміни Vim так: Помістіть курсор у перший рядок і введіть у звичайному режимі:

:.,/fff/s/\n.*\(\n.*\)/\1/g
  • .,/fff/Є діапазон для заміщення. Це означає "від цього рядка до рядка, що відповідає регулярному виразуfff (в даному випадку останньому рядку).
  • s///є заміною команди. Він шукає регулярний вираз і замінює кожне його появу рядком. ThegНа кінцях засобів повторити заміну тих пір , поки регулярний вираз продовжує бути знайдено.
  • Звичайний вираз \n.*\(\n.*\)відповідає .*новому рядку , потім цілому рядку ( відповідає довільній кількості символів, крім нового рядка), потім іншому новому рядку та іншому рядку. Дужки \(і \)спричиняють запис виразу всередині них, тому ми можемо використовувати його пізніше, використовуючи\1 .
  • \1 вставляє згрупований новий рядок і рядок після нього назад, тому що ми не хочемо, щоб пройшов і наступний рядок - ми просто хочемо, щоб механізм заміщення пройшов повз нього, щоб ми не видаляли його під час наступної заміни.

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


Або $замість /fff/, для кінця файлу, незалежно від його вмісту.
ефемієнт

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, і наступний рядок зникне

Я знаю, що це брудно, але це vim, і це працює


Прозорий, як грязь. Дякую!
Генрі Генрінсон,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.