Ваша проблема с Vim в том, что вы не любите vi .
Вы упоминаете обрезание yy
и жалуетесь, что почти никогда не хотите разрезать целые строки. На самом деле программисты, редактируя исходный код, очень часто хотят работать над целыми строками, диапазонами строк и блоками кода. Тем не менее, yy
это только один из многих способов вернуть текст в буфер анонимного копирования (или «зарегистрироваться», как он называется в vi ).
«Дзен» vi - это то, что вы говорите на языке. Инициал y
- это глагол. Заявление yy
является синонимом для y_
. Символ y
удваивается, чтобы его было легче набирать, поскольку это такая распространенная операция.
Это также может быть выражено как dd
P
(удалить текущую строку и вставить копию обратно на место; оставив копию в анонимном регистре в качестве побочного эффекта). В качестве «субъекта» y
и d
«глаголы» принимают любое движение. Таким образом, yW
это «дергать отсюда (курсор) до конца текущего / следующего (большого) слова» и y'a
«дергать отсюда до строки, содержащей метку с именем« а ».»
Если вы понимаете только основные движения курсора вверх, вниз, влево и вправо, тогда vi будет для вас не более продуктивной, чем копия «блокнота». (Хорошо, у вас все равно будет подсветка синтаксиса и возможность обрабатывать файлы размером более 45 КБ или около того; но поработайте со мной здесь).
У vi есть 26 «отметок» и 26 «регистров». Метка устанавливается в любом месте курсора с помощью m
команды. Каждый знак обозначается одной строчной буквой. Таким образом, ma
устанавливает метку ' a ' для текущего местоположения и mz
устанавливает метку ' z '. Вы можете перейти к строке, содержащей метку, используя команду '
(одинарная кавычка). Таким образом, 'a
перемещается в начало строки, содержащей знак « а ». Вы можете перейти к точному местоположению любой метки с помощью команды `
(обратная цитата). Таким образом `z
, переместимся непосредственно к точному местоположению знака « z ».
Поскольку это «движения», их также можно использовать в качестве субъектов для других «утверждений».
Таким образом, один из способов вырезать произвольную выделенную часть текста - сбросить метку (я обычно использую « a » в качестве моей «первой» метки, « z » в качестве моей следующей метки, « b » в качестве другой и « e » в качестве еще один (я не помню, чтобы когда-либо интерактивно использовалось более четырех меток за 15 лет использования vi ; каждый создает свои собственные соглашения относительно того, как метки и регистры используются макросами, которые не нарушают интерактивный контекст). Затем мы идем к другому концу нашего желаемого текста; мы можем начать с любого конца, это не имеет значения. Тогда мы можем просто использовать, d`a
чтобы вырезать или y`a
скопировать. Таким образом, весь процесс имеет накладные расходы на 5 нажатий клавиш (шесть, если мы начали в «вставить» "режим и необходимоEscвыход из командного режима). После того, как мы вырезать или копировать затем вставить в копии является Однократное нажатие клавиши: p
.
Я говорю, что это один из способов вырезать или скопировать текст. Тем не менее, это только один из многих. Часто мы можем более кратко описать диапазон текста, не перемещая курсор и не опуская метку. Например, если я нахожусь в абзаце текста, я могу использовать {
и }
перемещения в начало или конец абзаца соответственно. Итак, чтобы переместить абзац текста, я вырезал его с помощью {
d}
(3 нажатия клавиш). (Если я уже нахожусь в первой или последней строке абзаца, я могу просто использовать d}
или d{
соответственно.
Понятие «абзац» по умолчанию подразумевает нечто интуитивно разумное. Таким образом, это часто работает как для кода, так и для прозы.
Часто мы знаем какой-то шаблон (регулярное выражение), который отмечает один или другой конец текста, который нас интересует. Поиск вперед или назад - это движения в vi . Таким образом, они также могут быть использованы в качестве «субъектов» в наших «заявлениях». Поэтому я могу использовать d/foo
для вырезания из текущей строки в следующую строку, содержащую строку «foo», и y?bar
для копирования из текущей строки в самую последнюю (предыдущую) строку, содержащую «bar». Если мне не нужны целые строки, я все равно могу использовать поисковые движения (как свои собственные операторы), убрать свои отметки и использовать `x
команды, как описано ранее.
В дополнение к «глаголам» и «субъектам» в vi также есть «объекты» (в грамматическом смысле этого термина). Пока я только описал использование анонимного регистра. Однако я могу использовать любой из 26 «именованных» регистров, добавив префикс «object» "
(модификатор двойной кавычки). Таким образом, если я использую, "add
я обрезаю текущую строку в регистр ' a ', а если я использую, "by/foo
то я копирую копию текста отсюда на следующую строку, содержащую "foo", в регистр ' b '. Чтобы вставить из регистра, я просто добавляю префикс с той же самой последовательностью модификаторов: "ap
вставляет копию ' a ' регистра '"bP
вставляет копию от ' b ' до текущей строки.
Это понятие «префиксы» также добавляет аналоги грамматических «прилагательных» и «наречий» к нашему языку манипулирования текстом. «Большинство команд (глаголов) и движения (глаголы или объекты, в зависимости от контекста) также могут принимать числовые префиксы. Таким образом 3J
означает «соединить следующие три строки» и d5}
означает «удалить с текущей строки до конца пятого абзаца вниз отсюда».
Это все промежуточный уровень vi . Ничего из этого не относится к Vim, и в vi есть гораздо более сложные приемы, если вы готовы их изучить. Если бы вы освоили только эти промежуточные понятия, то вы, вероятно, обнаружили бы, что вам редко нужно писать какие-либо макросы, потому что язык манипулирования текстом достаточно лаконичен и выразителен, чтобы делать большинство вещей достаточно легко, используя «родной» язык редактора.
Выборка из более продвинутых трюков:
Существует ряд :
команд, в первую очередь метод :% s/foo/bar/g
глобальной замены. (Это не продвинутый, но другие :
команды могут быть). Весь :
набор команд был исторически унаследован предыдущими воплощениями vi как ed (редактор строк), а затем утилиты ex (редактор расширенных строк). На самом деле vi назван так, потому что это визуальный интерфейс для ex .
:
команды обычно работают над строками текста. ed и ex были написаны в эпоху, когда экраны терминалов были необычными, и многие терминалы были «телетайпными» (TTY) устройствами. Таким образом, было принято работать с печатными копиями текста, используя команды через чрезвычайно краткий интерфейс (общие скорости соединения составляли 110 бод, или, примерно, 11 символов в секунду - что медленнее, чем у быстрой машинистки; лаги были распространены на многопользовательские интерактивные сеансы, кроме того, часто была некоторая мотивация для экономии бумаги).
Таким образом, синтаксис большинства :
команд включает адрес или диапазон адресов (номер строки), за которыми следует команда. Естественно, можно использовать буквальные номера строк: :127,215 s/foo/bar
чтобы заменить первое вхождение «foo» на «bar» в каждой строке между 127 и 215. Можно также использовать некоторые сокращения, такие как .
или $
для текущей и последней строк соответственно. Можно также использовать относительные префиксы +
и -
ссылаться на смещения после или до текущей строки, соответственно. Таким образом: :.,$j
означает «от текущей строки до последней строки, объединить их все в одну строку». :%
является синонимом :1,$
(все строки).
:... g
И :... v
команды несут какое - то объяснение , как они невероятно сильны. :... g
является префиксом для «глобального» применения последующей команды ко всем строкам, которые соответствуют шаблону (регулярному выражению), в то время как :... v
такая команда применяется ко всем строкам, которые НЕ соответствуют данному шаблону («v» из «conVerse»). Как и в случае с другими командами ex, перед ними можно указывать адреса / ссылки на диапазон. Таким образом, :.,+21g/foo/d
означает «удалить любые строки, содержащие строку« foo », из текущей до следующих 21 строк», в то время как :.,$v/bar/d
означает «отсюда до конца файла» удалить все строки, которые НЕ содержат строку «bar».
Интересно, что обычная команда Unix grep была вдохновлена этой бывшей командой (и названа в честь того, как она была задокументирована). Экс команда :g/re/p
(Grep) был способ , которым они задокументированы , как «глобально» «печать» строки , содержащие «регулярное выражение» (ре). Когда использовались ed и ex , :p
команда была одной из первых, которую кто-либо узнал, и часто первой, которая использовалась при редактировании любого файла. Это было то, как вы печатали текущее содержимое (обычно только одну страницу за раз, используя :.,+25p
или что-то подобное).
Обратите внимание, что :% g/.../d
или (его аналог reVerse / conVerse: :% v/.../d
являются наиболее распространенными шаблонами использования. Однако есть пара других ex
команд, которые стоит запомнить:
Мы можем использовать m
для перемещения строк и j
объединения линий. Например, если у вас есть список, и вы хотите отделить все элементы, соответствующие (или наоборот НЕ соответствующие некоторому шаблону), не удаляя их, то вы можете использовать что-то вроде: :% g/foo/m$
... ... и все строки "foo" будут перемещены в конец файла. (Обратите внимание на другой совет об использовании конца вашего файла в качестве пустого места). Это сохранит относительный порядок всех строк «foo», извлекая их из остальной части списка. (Это было бы эквивалентно выполнению чего-то вроде: 1G!GGmap!Ggrep foo<ENTER>1G:1,'a g/foo'/d
(скопируйте файл в его собственный хвост, отфильтруйте хвост grep
и удалите все вещи из головы).
Чтобы соединить строки, обычно я могу найти шаблон для всех строк, которые должны быть соединены с их предшественником (например, все строки, которые начинаются с «^», а не с «^ *» в некотором списке маркеров). Для этого случая я бы использовал: :% g/^ /-1j
(для каждой подходящей строки, поднимитесь на одну строку и присоединитесь к ним). (Кстати: для маркированных списков , пытаясь найти пулевые линии и присоединиться к другому не работает по нескольким причинам ... он может присоединиться к одной пуле линии к другой, и он не будет вступать в любой пулевой линии для всех из его продолжения; он будет работать только на матчах).
Почти нет необходимости упоминать, что вы можете использовать нашего старого друга s
(заменить) с помощью команд g
и v
(глобальный / обратный глобальный). Обычно вам не нужно этого делать. Однако рассмотрим случай, когда вы хотите выполнить подстановку только в строках, соответствующих другому шаблону. Часто вы можете использовать сложный шаблон с захватами и обратные ссылки, чтобы сохранить части строк, которые вы НЕ хотите изменять. Однако часто будет проще отделить совпадение от подстановки: :% g/foo/s/bar/zzz/g
- для каждой строки, содержащей «foo», заменить все «bar» на «zzz». (Что-то вроде:% s/\(.*foo.*\)bar\(.*\)/\1zzz\2/g
будет работать только для случаев те экземпляры "bar", которые были PRECEDED "foo" в той же строке; это уже достаточно неуклюже, и его пришлось бы покалечить, чтобы поймать все случаи, когда «bar» предшествовал «foo»)
Дело в том , что есть больше , чем просто p
, s
и d
строки в ex
наборе команд.
В :
адресе может также относиться к отметкам. Таким образом, вы можете использовать: :'a,'bg/foo/j
для присоединения любой строки, содержащей строку foo, к ее последующей строке, если она лежит между строками между метками « a » и « b ». (Да, все предыдущие ex
примеры команд могут быть ограничены подмножествами строк файла путем добавления префиксов к этим видам выражений адресации).
Это довольно неясно (за последние 15 лет я использовал что-то подобное несколько раз). Тем не менее, я свободно признаю, что часто делал вещи итеративно и интерактивно, что, возможно, могло бы быть сделано более эффективно, если бы я нашел время, чтобы продумать правильное заклинание.
Другая очень полезная команда vi или ex - :r
это чтение содержимого другого файла. Таким образом: :r foo
вставляет содержимое файла с именем «foo» в текущую строку.
Более мощная :r!
команда. Это читает результаты команды. Это то же самое, что приостановка сеанса vi , выполнение команды, перенаправление ее вывода во временный файл, возобновление сеанса vi и чтение содержимого из temp. файл.
Еще более мощными являются команды !
(bang) и :... !
( ex bang). Они также выполняют внешние команды и считывают результаты в текущий текст. Тем не менее, они также фильтруют выбор нашего текста через команду! Таким образом, мы можем отсортировать все строки в нашем файле с помощью 1G!Gsort
( G
это команда vi "goto"; по умолчанию она идет до последней строки файла, но может начинаться с префикса по номеру строки, например, 1, первая строка). Это эквивалентно бывшему варианту :1,$!sort
. Авторы часто используют утилиты !
Unix fmt или fold для переформатирования или «переноса слов» выделенных фрагментов текста. Очень распространенный макрос{!}fmt
(переформатировать текущий абзац). Программисты иногда используют его для запуска своего кода или только его частей через отступ или другие инструменты переформатирования кода.
Использование :r!
и !
команды означают , что любая внешняя полезность или фильтр может рассматриваться как расширение нашего редактора. Я иногда использовал их со скриптами, которые извлекали данные из базы данных, или с командами wget или lynx, которые извлекали данные с веб-сайта, или с командами ssh, которые извлекали данные из удаленных систем.
Еще одна полезная команда ex:so
(сокращение от :source
). Это читает содержимое файла как последовательность команд. Когда вы запускаете vi, он обычно неявно выполняет :source
включение ~/.exinitrc
файла (и Vim обычно делает это ~/.vimrc
, естественно). Использование этого в том, что вы можете изменить свой профиль редактора на лету, просто используя новый набор макросов, сокращений и настроек редактора. Если вы подлый, вы можете даже использовать это как трюк для хранения последовательностей бывших команд редактирования для применения к файлам по требованию.
Например, у меня есть файл из семи строк (36 символов), который запускает файл через wc и вставляет комментарий в стиле C вверху файла, содержащего данные подсчета слов. Я могу применить этот «макрос» к файлу с помощью команды вроде:vim +'so mymacro.ex' ./mytarget
(Параметр +
командной строки для vi и Vim обычно используется для запуска сеанса редактирования с заданным номером строки. Однако малоизвестный факт, что можно следовать за +
любой действительной командой / выражением ex , такой как команда «source», как Я сделал здесь, для простого примера у меня есть сценарии, которые вызывают: vi +'/foo/d|wq!' ~/.ssh/known_hosts
удалить запись из моего известного SSH-файла хостов неинтерактивно, пока я перезаписываю набор серверов).
Обычно гораздо проще писать такие «макросы», используя Perl, AWK, sed (что на самом деле похоже на утилиту grep, вдохновленную командой ed ).
Команда, @
вероятно, самая неясная команда vi . Периодически преподавая курсы по системному администрированию в течение почти десятилетия, я встречал очень мало людей, которые когда-либо пользовались им. @
выполняет содержимое регистра, как если бы это была команда vi или ex .
Пример: я часто использую: :r!locate ...
чтобы найти какой-нибудь файл в моей системе и прочитать его имя в моем документе. Оттуда я удаляю любые посторонние попадания, оставляя только полный путь к интересующему меня файлу. Вместо того, чтобы кропотливо Tabпроходить через каждый компонент пути (или, что еще хуже, если я застрял на машине без поддержки завершения Tab в его копии vi ) я просто использую:
0i:r
(чтобы превратить текущую строку в правильную команду : r ),
"cdd
(удалить строку в регистр "c") и
@c
выполнить эту команду.
Это всего лишь 10 нажатий клавиш (и это выражение "cdd
@c
для меня фактически является макросом пальца, поэтому я могу набрать его почти так же быстро, как и любое обычное шестибуквенное слово).
Отрезвляющая мысль
Я только поверхностно рассмотрел силу vi , и ни одно из того, что я здесь описал, даже не является частью "улучшений", для которых назван vim ! Все, что я здесь описал, должно работать на любой старой копии vi 20 или 30 лет назад.
Есть люди, которые использовали значительно больше силы Ви , чем я когда-либо буду.