lonelyelk
lonelyelk

Reputation: 578

vim script leaves characters in stdin

I'm trying to use vim with -s option to run a script that replaces some lines in a file like this (text.txt):

test1
ab
ac
ae
test2
sd

Script file is like this (script):

:silent %s/test1\zs\_.\+\zetest2/\=substitute(submatch(0), '\n\(\w\)', '\n#\1', 'g')/g
:wq

It comments out lines between test1 and test2. Which is what I want. What I don't want though is output before and after prompt. I run it and get:

user@hostname: ~/vimtest$ vim -s script text.txt 
^[[?1;2cuser@hostname: ~/vimtest$ 1;2c

So this ^[[?1;2c is bad news already but 1;2c is in the input as if I already typed it. If I hit enter it gives me a bash error. So I have to remove these symbols each time the script is used. Any ideas?

Upvotes: 0

Views: 318

Answers (3)

rici
rici

Reputation: 241671

It seems like vim (or some vim startup script) is trying to figure out what type of terminal you are using. The ^[[?1;2c, with the last few characters left in the input buffer, is almost certainly part of your terminal emulator's response to a DA (Device Attributes) query. You can see this yourself by typing in bash:

printf '\033[c'

or, to see the complete return, pause a bit:

printf '\033[c'; sleep 0.1; echo

The response \033[?1;2c means "I'm a VT100 with Advanced Video Option.", which is what xterm and many other console programs respond. (The Linux console itself responds \033[?6c, which means "I'm a VT102.")

The reason that only 1;2c is left in the console input buffer, by the way, is that the initial escape code \033[? was ignored when it was read. The readline library will ignore it without echoing it, whereas normal console input will echo it and then ignore it; that's why the two shell commands above differ.

I can't reproduce this problem with my vim installation, so I don't really even know where to start looking. But you might try to see if disabling all startup files helps:

vim -u NONE -s script text.txt

If that helps, start disabling installed extensions one by one until you find the one which is causing the problem.

Upvotes: 2

Kent
Kent

Reputation: 195029

I noticed that you tagged the question with bash, so I thought a shell-solution should be accepted too.

awk '/test1/{p=1;print;next}/test2/{p=0;print;next}{$0=(p?"#":"")$0}7' file

this awk oneliner should do that for you. vim is very powerful editor, I love vim. But if you want to do some automatic transformation, I prefer a script or a proper text processing tool. On a linux box you can always find one. It is easier to test and debug.

Test with your input:

kent$  cat f
test1
ab
ac
ae
test2
sd

kent$  awk '/test1/{p=1;print;next}/test2/{p=0;print;next}{$0=(p?"#":"")$0}7' f
test1
#ab
#ac
#ae
test2
sd

If you want to save the text back to your file, you can :

awk '...' file > tmp.file && mv tmp.file file

Upvotes: 1

Kent
Kent

Reputation: 195029

:%s/test1\zs\_.\+\ze\ntest2/\=substitute(submatch(0), '\n', '\n#', 'g')/g
:wq

this is tested here, it changed the input file in required way.

Some changes done based on your command:

  • add \n after \ze
  • in substitute() function we can just handle the \n, we don't need to capture the word after the \n

Upvotes: 1

Related Questions