user2567544
user2567544

Reputation: 587

How to conditionally edit files in vim

I have a requirement to batch edit a bunch of files using vim based on their content. The simplest example is that I'd like to perform a series of let's say substitutions on files but only if the first line of the file matches a certain pattern.

I'm trying to do this kind of thing:

vim -e -s $file < changes.vim

I should add that I have no access to tools like sed and awk and would like to perform the entire operation in vim.

Upvotes: 2

Views: 220

Answers (3)

Ingo Karkat
Ingo Karkat

Reputation: 172570

Within Vim, you can determine the matching files via :vimgrep; to check for a match in the first line, the \%l atom is handy:

:vimgrep /\%1lcertain pattern/ {file-glob}

Then, you can iterate through all matches with :cfnext, or use the :QFDo command from here.

You can pass those commands either via vim -c {cmd} -c {cmd} ..., or in a separate script, as you outline in your question.

Upvotes: 0

Floris
Floris

Reputation: 46375

I recommend that you find the list of files you need, and pass that list into the command you want. For this, a combination of awk and xargs would seem useful. There are probably clever shorter things you can do…

awk 'FNR>1 {nextfile} /pattern/ { print FILENAME ; nextfile }' filePattern | xargs -I{} vim -e -s {} < changes.vim

In the above, filePattern gives all the files you want (maybe *.c), /pattern/ is the regex of the match you are looking for. xargs will take "one output at a time" and substitute it into the following command at the place where I put the {}.

I want to give a tip of the hat to this link where I found the inspiration for this answer.

vim only solution

EDIT - after I posted this you said you need a "vim only" solution. Here it is…

Step 1: create a conditionalEdits.vim file with the following lines at the start:

let line_num = search('searchExpression')  " any regex 
if line_num == 1                           " first line matched
  center                                   " put your editing commands here...
  update                                   " save changes
endif
quit

Of course, instead of just centering the first line, you will want to put all your editing commands inside the if statement.

Now, you execute this command with

vim -c '/path/to/my/conditionalEdits.vim' -s filePattern

where filePattern matches all the files you might be interested in (but you will know for sure after you have looked at line 1 inside…)

Obviously you can navigate through the file in the usual way and look for matches / patterns etc to your heart's content - but this is the basic idea.

Helpful links: http://www.ibm.com/developerworks/library/l-vim-script-1/ and http://learnvimscriptthehardway.stevelosh.com

I highly recommend that you do this in a separate directory, using copies of a handful of files first, to make sure this actually does what you think it does. I would hate to be responsible for a bunch of files being overwritten (you do back up, right?)

Upvotes: 1

pfnuesel
pfnuesel

Reputation: 15310

You can loop over all files, if you find the pattern, open vim. Once it is modified to your needs and closed, the next one will open.

#!/usr/bin/env bash

for file in *; do
    if [[ "$(sed '1q' ${file})" == "pattern" ]]; then
        vim ${file}
    fi
done

Upvotes: 1

Related Questions