0

This is my first-post and question here so please be gentle (but also tell me if, it I wasn't specific enough etc...)

So my questions seems rather simple to me, but still blocks me and I can't find anything in the net helping me (for the first time in my life kind of..)

I simply have to edit many (~100) files. I have to search a certain string, change it and copy a certain amount of lines after that string to another file.
Instead of writing some sort of parser that reads the whole file (with python or similar) I found it quite convenient to use the -E mode of vim inside a bash script to do the job.

So what I do is, to write all the commands that I want vim to execute to a script and then source it to vim. The script looks like this:

:%s/string/string$i/g #Search the string append a running number to it 
V      # Go to visiual line mode 
19j    # Jump 19 lines 
y      # yank the lines
:vs output.file # open the file where I need to copy the lines
G      # go to the end
p      # pass the lines
:wqa   # save and close everything

However, this works only in the normal vim mode e.G. if I execute vim like this

vim -s vim.scr file-to-edit

which is quite annoying because every time a file is edited a vim window is opened.

It doesn't work, if I use -E mode like

vim -E -s file-to-edit < vim.scr

or

vim -E -s -c "source vim.scr" file-to-edit

From the documentation I understand that the Ex modes only executes colon commands (which makes sense, that it doesn't execute the visual ones..)

 *41.1* Introduction                *vim-script-intro* *script* 

Your first experience with Vim scripts is the vimrc file.  Vim reads it when
it starts up and executes the commands.  You can set options to values you
prefer.  And you can use any colon command in it (commands that start with a
":"; these are sometimes referred to as Ex commands or command-line commands).

So my question basically is, how can I replace all the non-colon commands in my script above to make vim -E -s [...], to do what I want?

Thanks for your help!

Cheers, Marcus

1

I didn't test it but you need to use :h :norm:

:norm[al][!] {commands}                 *:norm* *:normal*
            Execute Normal mode commands {commands}.  This makes
            it possible to execute Normal mode commands typed on
            the command-line.  {commands} are executed like they
            are typed.  For undo all commands are undone together.
            Execution stops when an error is encountered.

Which would give you the following file:

%s/string/string$i/g
norm! V
norm! 19j
norm! y
vs output.file
norm! G
norm! p
wqa

Also note that you don't need to put : in front of your normal mode command when they are written in a script.

Also, for what it's worth I would not use Vim for what you are trying to do. I think grep with the -A parameter would be enough to get only the 19 lines after your matched string. And you can pipe it to sed to do you substitution.

Probably something along the lines of

grep -A 19 "string" file-to-edit | sed 's/string/string$i/' > output.file

If you have many files this should me faster because grep and sed are specialized for these tasks and should be better than Vim. Also since you are now in the terminal you can use the * joker to treat all of your files.

  • 1
    Thanks a lot for the quick reply! Your suggestion for the vim-script works. I might also try your suggestion using grep and sed. However, since the number of files and lines to yank isn't that large it only takes a few seconds using vim... – Marcus Schmitt Dec 11 '18 at 11:01
1

You can yank and put lines directly from the command-line without using any normal-mode commands:

Try the following:

%s/string/string$i/g
.,+19y           # yank the current line and the 19 lines that follow
vs output.file
$pu              # put the lines at the end of the buffer
wqa

See :help :yank, :help :put and :help [range] for more details.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.