Vim. Одновременное изменение нескольких файлов. Развернутый пример с комментариями

    Бывают ситуации когда нужно выполнить какую-то последовательность действий одновременно в нескольких файлах. Конечно, для этого можно использовать разные инструменты (навскидку: bash + sed/awk, python/perl, ...) — какие-то будут менее приспособлены для выполнения поставленной задачи, какие-то — более. Сейчас мы рассмотрим пример решения одной такой простой задачи средствами редактора Vim.

    Рассмотрим простой пример: вставка строки в начало каждого файла.

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

    Итак, приступим:

    1. Открываем в редакторе все файлы в которых нужно сделать изменения:

    $ vim -o file1.txt file2.txt file3.txt

    Опция -o дает возможность открыть каждый файл в отдельном окне. Запуск с данной опцией в примере сделан не только для наглядности (все изменения будут видны сразу), но и исходя из еще одного момента о котором будет сказано ниже.

    2. Записываем последовательность действий которую необходимо проделать над файлами в макрос:

    qm1GOПервая строка<ESC>qu

    qm — начало записи макроса в регистр m
    1G — переход на первую строку файла
    O (большая латинская буква O) — вставка строки перед текущей строкой с переходом в режим редактирования
    Первая строка — содержание первой строки
    <ESC> — выход из режима редактирования
    q — окончание записи макроса
    u — отмена изменений в текущем окне во избежания дублирования сделанных изменений

    3. Запуск макроса m во всех окнах:

    :windo normal @m

    windo — команда запуска команды vim во всех окнах
    normal — команда запуска команды нормального режима vim из командной строки, то есть две команды запуска макроса эквиваленты:
    @m
    :normal @m

    Если бы мы просто сделали так:
    :windo @m
    то мы бы получили сообщение об ошибке «Это не команда редактора»
    по сути мы бы в каждом окне выполнили такое действие:
    : @m
    что является неверным, поскольку мы запускаем команду нормального режима в командной строке. В итоге мы можем получить либо сообщение об ошибке либо непредсказуемые действия редактора.

    Есть команды, аналогичные :windo:
    :argdo
    :tabdo
    :bufdo

    Первая команда — :argdo. Мощная команда, которая позволяет выполнить команду в списке файлов заданном как именованный аргумент. Здесь мы ее рассматривать не будем.
    Вторая команда — :tabdo. Полностью аналогична нашей windo, но проделывает всю работы над всеми открытыми вкладками. Тут есть один момент о котором стоит упомянуть: в каждой вкладке может быть несколько окон. Так вот, изменения будут только в текущем окне каждой вкладки!
    Ну инаконец третья команда — :bufdo. Выполняет команду над всеми буферами. Но при ее использовании есть один нюанс. Сама команда bufdo выполнится только в текущем буфере и завершится с ошибкой если «полезная» команда (та, которую запускает bufdo и которая должна выполниться в каждом буфере) изменяет текст.

    Например так:
    :bufdo normal G
    выполнится нормально во всех буферах
    а вот так так:
    :bufdo normal GoEnd file
    уже завершится с ошибкой. Что бы все заработало надо сделать так:
    :bufdo! normal GoEnd file

    Собственно это все на сегодня. За мой первый пост на хабре ногами прошу не пинать. Исправления, дополнения, замечания — приветствуются.

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 18

    • UFO just landed and posted this here
        0
        Даже рутинная работа превращается в интересный квест с необходимостью повышенного внимания (режимы).
        +1
        А я начал знакомство с Linux с освоения vim. Редактор невероятно удобный, когда привыкнешь, но неинтуитивный интерфейс многих отпугивает ).

        Про работу одновременно в нескольких вкладках даже не подозревал (хотя может оно мне не так сильно и нужно было...), так что автору респект!
          0
          А я постоянно пользуюсь табами.
          Выставляю горячую клавишу <Сtrl> O на открытие нового таба:
            0
            А я постоянно пользуюсь табами(:tabnew).
            Выставляю горячую клавишу <Сtrl> O на открытие нового таба:
            nmap <C-o> :tabnew
            И для открытия нового таба использую функцию:
            :set tabline=%!ShortTabLine()

            function ShortTabLine()
            let ret = ''
            for i in range(tabpagenr('$'))
            " select the color group for highlighting active tab
            if i + 1 == tabpagenr()
            let ret .= '%#errorMsg#'
            else
            let ret .= '%#TabLine#'
            endif
            " find the buffername for the tablabel
            let buflist = tabpagebuflist(i+1)
            let winnr = tabpagewinnr(i+1)
            let buffername = bufname(buflist[winnr-1])
            let filename = fnamemodify(buffername,':t')
            " check if there is no name
            if filename == ''
            let filename = 'noname'
            endif
            " only show the first 6 letters of the name and
            "… if the filename is more than 8 letters long
            if strlen(filename) >=8
            let ret .= '['. filename[0:5].'..]'
            else
            let ret .= '['.filename.']'
            endif
            endfor
            " after the last tab fill with TabLineFill and reset tab page #
            let ret .= '%#TabLineFill#%T'
            return ret
            endfunction
              +1
              Замена текста во всех буферах:

              :bufdo %s/pattern/substitution/ge | update
                0
                Спасибо… еще один маленький шаг в переходе на vim для меня.
                  +1
                  Пользуюсь vim-ом время от времени на примитивном уровне по необходимости.

                  Прочитав статью, понял, что использование подобных финтов на автопилоте сравнимо с владением техники карате на уровне первого дана. Количество нюансов, конечно, воображение потрясает, но понимаешь, что шансов дотянуться до подобной виртуозности крайне мало.
                    0
                    это точно не про меня. выучил только базовые возможности vim'а, только те которые сильно влияют на производительность труда (все от лени-матушки, от неё, родимой). вообще думаю, что реально в голове оседает только то, чем пользуешься сравнительно часто.

                    я например свой vimrc практически не менял, как писать vim-функции — не знаю. да и вообще много чего не знаю в этом редакторе, но то что знаю — очень здорово помогает в работе, избавляя от рутинной, монотонной работы, делая её немного творческой и даже забавной.

                    думаю, что у каждого есть свой «набор» похожих знаний и умений в «базовых» продуктах — таких как vim, bash, coreutils,… — те которые нужны в ежедневной работе и позволяют не отвлекаться на рутину.

                    надеюсь что своей статьей помог хотя-бы кому-нибудь дополнить свой «набор» и сделать свою работу хоть чуточку веселее, продуктивней
                      0
                      Веселее стало — спасибо.
                    0
                    На самом деле страшновато делать изменения в буферах, которые не видишь своими глазами, особенно если изменения несколько сложнее, чем вставка одной строки (с -o в реальности никогда файлы не открываю, только табы)

                    По старинке и с большим контролем это можно сделать, выполнив записанный макрос с помощью @m, и повторяя его во всех вкладках с помощью @@ — по времени, наверное, не сильно дольше, но совсем не страшно :)
                      0
                      Спасибо за статью, узнал о normal — очень удобная штука. Я не так давно начал учить Vim, сейчас как раз в процессе и чем дальше, тем интереснее :) На днях смотрел скринкаст именно на эту тему — Derek Wyatt на vimeo — Working with Many Files (Screencast 2). Примерно то же самое, только немного другими инструкциями + немного нагляднее.
                        0
                        Вот так короче, используя однострочник и нерассмотренный argdo (запись макроса в данном случае не нужна)

                        vim -c ":argdo 1norm! OПервая строка" file1.txt file2.txt file3.txt
                        
                          0
                          А есть вариант наоборот, открыть файл из командной строки чтобы он не открывал отдельное окно, а просто добавился в открытый вим в виде вкладки или буфера?
                          (имеется в виду извне вима, а не :e blahblahbla\file.txt)
                            +1
                            конечно; man vim на тему --remote*
                              0
                              Винда)
                                +1
                                :help remote
                                  0
                                  Всё-всё, разобрался уже)) спасибо огромное!!!

                          Only users with full accounts can post comments. Log in, please.