Ваша проблема з Vim полягає в тому, що ви не громіть vi .
Ви згадуєте різання yy
і скаржитеся, що майже ніколи не хочете різати цілі лінії. Насправді програмісти, редагуючи вихідний код, дуже часто хочуть працювати над цілими рядками, діапазонами рядків і блоками коду. Однак yy
це лише один із багатьох способів перетягування тексту в буфер анонімної копії (або "реєстрація", як це називається in vi ).
"Дзен" vi полягає в тому, що ти розмовляєш мовою. Початкова y
- дієслово. Заява yy
є синонімом для y_
. Це y
вдвічі збільшується для полегшення набору тексту, оскільки це така звичайна операція.
Це також можна виразити як dd
P
(видалити поточний рядок і вставити копію на місце; залишити копію в анонімному реєстрі як побічний ефект). В y
і d
«дієслова» приймати будь - якого руху в якості «суб'єкта». Таким чином yW
, "yank звідси (курсор) до кінця поточного / наступного (великого) слова" і y'a
"yank звідси до рядка, що містить позначку" a ".
Якщо ви розумієте лише основні рухи курсору вгору, вниз, вліво та вправо, то vi буде для вас не продуктивнішим, ніж копія «блокнота». (Гаразд, ви все одно матимете підсвічування синтаксису та можливість обробляти файли, розміри яких більший за загадку ~ 45 Кб або близько того; але працюйте зі мною тут).
vi має 26 "знаків" та 26 "регістрів". Позначення встановлюється в будь-якому місці курсору за допомогою m
команди. Кожен знак позначається однією малою літерою. Таким чином, ma
встановлює позначку ' a ' поточному розташуванню та mz
встановлює позначку ' z '. Ви можете перейти до рядка, що містить позначку, за допомогою команди '
(одна цитата). Таким чином, 'a
переходить до початку рядка, що містить позначку ' a '. Ви можете переміститися в точне місце розташування будь-якої марки за допомогою команди `
(backquote). Таким чином, `z
буде переміщено безпосередньо до точного місця знака ' z '.
Оскільки це "рухи", вони також можуть бути використані в якості предметів для інших "тверджень".
Отже, одним із способів вирізати довільний відбір тексту буде скидання позначки (я зазвичай використовую " a " як мій "перший" знак, " z " як наступний знак, " b " як інший, і " e " як ще інший (я не пам'ятаю, щоб коли-небудь інтерактивно використовував більше чотирьох знаків за 15 років використання vi ; створюється власна конвенція щодо того, як знаки та регістри використовуються макросами, які не порушують чийсь інтерактивний контекст). на інший кінець потрібного нам тексту; ми можемо починати з будь-якого кінця, це не має значення. Тоді ми можемо просто використовувати d`a
для вирізання або y`a
копіювання. Таким чином, весь процес має 5 натискань клавіш накладними (шість, якщо ми починаємо з "вставити" "режим і потрібноEscвихідний режим команд). Після того, як ми вирізати або копіювати потім вставити в копії є Натискання клавіші: p
.
Я кажу, що це один із способів вирізати чи скопіювати текст. Однак це лише одна з багатьох. Часто ми можемо більш коротко описати діапазон тексту, не переміщуючи курсор навколо і не скидаючи позначку. Наприклад, якщо я перебуваю в абзаці тексту, я можу використовувати {
і }
переміщення до початку або в кінці абзацу відповідно. Отже, для переміщення абзацу тексту я вирізав його за допомогою {
d}
(3 натискання клавіш). (Якщо у мене вже є перший або останній рядок абзацу, я можу просто використовувати d}
або d{
відповідно.
Поняття "абзац" є типовим для інтуїтивно зрозумілого. Таким чином, він часто працює як для коду, так і для прози.
Часто ми знаємо деякий шаблон (регулярний вираз), який позначає той чи інший кінець тексту, в якому нас цікавлять. Пошук вперед або назад - це рухи in vi . Таким чином, вони також можуть бути використані як "суб'єкти" в наших "висловлюваннях". Тож я можу використовувати d/foo
для вирізання з поточного рядка до наступного рядка, що містить рядок "foo", і y?bar
копіювати з поточного рядка до останнього (попереднього) рядка, що містить "bar". Якщо я не хочу цілі рядки, я все ще можу використовувати рухи пошуку (як власні висловлювання), опускати мітку (и) та використовувати `x
команди, як описано раніше.
Окрім «дієслів» та «предметів» vi також має «предмети» (у граматичному значенні цього терміна). Поки що я описав лише використання анонімного реєстру. Однак я можу використовувати будь-який з 26 "іменованих" регістрів, префіксуючи посилання "об'єкт" на "
(модифікатор подвійної лапки). Таким чином, якщо я використовую, "add
я вирізаю поточний рядок у регістрі ' a ', а якщо я використовую, "by/foo
то я перебираю копію тексту звідси в наступний рядок, що містить "foo", в регістр ' b '. Щоб вставити з регістра, я просто вставлю префікс в тій же послідовності модифікаторів: вставляє "ap
копію " a " регістру"bP
вставляє копію з " b " до поточного рядка.
Це поняття "префікси" також додає аналоги граматичних "прикметників" та "прислівників" до нашої мови "маніпулювання текстом". Більшість команд (дієслів) та руху (дієслова чи об'єкти, залежно від контексту) також можуть приймати числові префікси. Таким чином. 3J
означає "приєднатися до наступних трьох рядків" і d5}
означає "видалити з поточного рядка через кінець п’ятого абзацу вниз звідси".
Це все проміжний рівень vi . Жоден з них не є специфічним для Vim, і в vi є набагато більш досконалі трюки, якщо ви готові їх навчитися. Якби ви освоїли саме ці проміжні поняття, ви, мабуть, виявите, що вам рідко потрібно писати якісь макроси, оскільки мова маніпулювання текстом є достатньо стислою та виразною, щоб зробити більшість справ досить легко за допомогою "рідної" мови редактора.
Вибірка більш досконалих трюків:
Існує ряд :
команд, особливо :% s/foo/bar/g
глобальна техніка заміни. (Це не вдосконалено, але інші :
команди можуть бути). Весь :
набір команд був історично успадкований попередніми втіленнями vi як ed (редактор рядків), а пізніше екс- утиліти (розширений редактор рядків). Насправді vi так названий, тому що це візуальний інтерфейс до колишнього .
:
команди зазвичай працюють над рядками тексту. ed та ex були написані в епоху, коли екрани терміналів були рідкісними, і багато терміналів були пристроями "телетайпу" (TTY). Тож було прийнято працювати над друкованими копіями тексту, використовуючи команди через надзвичайно стислий інтерфейс (загальна швидкість з'єднання становила 110 бод, або, приблизно, 11 символів в секунду - що повільніше, ніж швидка друкарка; лаги були поширеними на багатокористувацькі інтерактивні сеанси; крім того, часто виникала мотивація до збереження паперу).
Отже, синтаксис більшості :
команд включає адресу або діапазон адрес (номер рядка), за якими слідує команда. Звичайно, можна використати буквальні номери рядків: :127,215 s/foo/bar
щоб змінити перше виникнення "foo" на "bar" на кожному рядку між 127 та 215. Можна також використовувати деякі абревіатури, такі як .
або $
для поточного та останнього рядків відповідно. Можна також використовувати відносні префікси +
та -
посилатися на зсуви після або перед лінією вилікування відповідно. Таким чином: :.,$j
означає "з поточного рядка до останнього рядка, з'єднайте їх усіх в один рядок". :%
є синонімом :1,$
(усі рядки).
Команди :... g
та :... v
команди несуть певне пояснення, оскільки вони неймовірно потужні. :... g
є префіксом "глобально", що застосовує наступну команду до всіх рядків, які відповідають шаблону (регулярний вираз), при цьому :... v
застосовує таку команду до всіх рядків, які НЕ відповідають заданому шаблону ("v" від "conVerse"). Як і у випадку з іншими колишніми командами, вони можуть бути встановлені префіксом шляхом адресації / діапазону посилань. Таким чином, :.,+21g/foo/d
означає "видалити будь-які рядки, що містять рядок" foo ", з поточного через наступні 21 рядок", а :.,$v/bar/d
означає "звідси до кінця файлу, видалити будь-які рядки, які не містять рядок" bar ".
Цікаво, що загальна команда grep для Unix насправді була натхненна цією командою ex (і названа так, як вона була задокументована). Екс команда :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
(global / converse-global). Зазвичай вам цього не потрібно. Однак розглянемо певний випадок, коли потрібно здійснити заміну лише на лініях, що відповідають деякому іншому шаблону. Часто ви можете використовувати складний візерунок із захопленнями та використовувати зворотні посилання, щоб зберегти частини рядків, які НЕ хочете змінювати. Однак, часто буде простіше відокремити матч від заміни: :% g/foo/s/bar/zzz/g
- для кожного рядка, що містить "foo", замініть усі "bar" на "zzz". (Щось на зразок:% s/\(.*foo.*\)bar\(.*\)/\1zzz\2/g
працюватиме лише у випадках, коли ті випадки "bar", які були визначені "foo" на тому ж рядку; це вже недостатньо вигідно, і його доведеться ще більше гнати, щоб спіймати всі випадки, коли "бар" передував "foo")
Справа в тому , що є більше , ніж просто p
, s
і d
рядки в ex
наборі команд.
В :
адресі може також ставитися до позначок. Таким чином, ви можете використовувати: :'a,'bg/foo/j
щоб приєднати будь-який рядок, що містить рядок foo, до його наступного рядка, якщо він лежить між рядками між знаками ' a ' та ' b '. (Так, всі попередні ex
приклади команд можуть бути обмежені підмножинами рядків файлу шляхом префіксації цих видів виразів адресації).
Це досить незрозуміло (я використовував щось подібне лише кілька разів за останні 15 років). Однак я вільно визнаю, що я часто робив ітеративні та інтерактивні речі, які, можливо, могли бути зроблені ефективніше, якби я знайшов час, щоб продумати правильний заклик.
Ще одна дуже корисна команда vi або ex - :r
це читати вміст іншого файлу. Таким чином: :r foo
вставляє вміст файла під назвою "foo" у поточному рядку.
Більш потужною є :r!
команда. Це читає результати команди. Це те саме, що призупиняти сеанс vi , виконувати команду, перенаправляти її вихід у тимчасовий файл, поновлювати сеанс vi та читати вміст із темп. файл.
Ще більш потужними є команди !
(bang) та :... !
( ex bang) команди. Вони також виконують зовнішні команди та читають результати у поточному тексті. Однак вони також фільтрують виділення нашого тексту за допомогою команди! Це ми можемо сортувати всі рядки у нашому файлі за допомогою 1G!Gsort
( G
це команда vi "goto"; вона за замовчуванням переходить до останнього рядка файла, але може бути встановлена префіксом за номером рядка, таким як 1, перший рядок). Це еквівалентно колишньому варіанту :1,$!sort
. Письменники часто використовують !
з Unix FMT або складіть утиліти для переформатування або «слово» упаковка вибору тексту. Дуже поширений макрос{!}fmt
(переформатувати поточний параграф). Інколи програмісти використовують його для запуску свого коду або просто його частини за допомогою відступів чи інших інструментів переформатування коду.
Використання команд :r!
і !
означає, що будь-яка зовнішня утиліта чи фільтр може розглядатися як розширення нашого редактора. Я періодично використовував їх із сценаріями, які витягували дані з бази даних, або з командами wget або lynx, які витягували дані з веб-сайту, або з командами ssh, які витягували дані з віддалених систем.
Ще одна корисна команда ex:so
(скорочена для :source
). Це читає вміст файлу у вигляді серії команд. Коли ви запускаєте vi, він нормально, неявно, виконує файл :source
на ~/.exinitrc
файл (а Vim зазвичай робить це ввімкнено ~/.vimrc
, досить природно). Використання цього полягає в тому, що ви можете змінити профіль свого редактора на ходу, просто знайшовши новий набір макросів, скорочень та налаштувань редактора. Якщо ви підлий ви можете навіть використовувати це як трюк для зберігання послідовностей екс редагування команди застосовуються до файлів на вимогу.
Наприклад, у мене є сім-рядковий файл (36 символів), який запускає файл через wc , і вставляє коментар у стилі С у верхній частині файлу, що містить дані про кількість слів. Я можу застосувати цей "макрос" до файлу, використовуючи команду типу:vim +'so mymacro.ex' ./mytarget
(Опція +
командного рядка vi та Vim зазвичай використовується для запуску сеансу редагування за заданим номером рядка. Однак маловідомий факт, що можна слідувати +
за будь-яким дійсним колишнім командою / виразом, таким як команда "джерело" як Я зробив тут; для простого прикладу я маю сценарії, які викликають: 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
виконати цю команду.
Це всього 10 натискань клавіш (і вираз "cdd
@c
- це фактично макрос пальця для мене, тому я можу ввести його майже так само швидко, як будь-яке загальне шість буквене слово).
Твереза думка
Я лише почухав поверхню енергії vi , і жодне з того, що я описав тут, навіть не є частиною "удосконалень", за якими названо vim ! Все, що я тут описав, має працювати на будь-якій старовинній копії vi від 20 до 30 років тому.
Є люди , які значно використовуються більш VI влади «s , ніж я коли - небудь буде.