Differences in running vim through the command line versus running it in the vim editor
I am trying to process a number of files. I noticed that there are discrepancies in the execution of a particular command from the command line (i.e. ex
mode). For example.
$cat poo.txt
big
red
dog
small
black
cat
$vim -c "2,$g/^dog/d|wq" poo.txt
$cat poo.txt
big
small
black
cat
It looks like I 2,$g/^dog/d|wq
removed the lines with red
and dog
. This confuses me because the command must: start on line 2 (go to EOF) and delete all lines starting with dog
. In this case, I expect the output to be as follows:
$ cat poo.txt big red small black cat
In fact, if I try this in the vim editor, this is the exact behavior that is observed.
QUESTION: What is the reason for the mismatch between version vim -c
and version vim
to run this command?
source to share
I think you need to replace double quotes with single quotes to prevent shell expansion $g
. From man bash
:
Enclosing characters in double quotes preserves the literal value of all
characters within the quotes, with the exception of $, `, \, and,
when history expansion is enabled, !.
Currently your shell expands $g
inside your string as if it were an environment variable. But it is probably undefined, thus expanding to an empty string. So, even if you typed:
vim -c "2,$g/^dog/d|wq" poo.txt
Vim does not receive the command:
2,$g/^dog/d|wq
... but:
2,/^dog/d|wq
This command removes all lines from those whose address 2
to the next one that starts with dog
(in your case, this is the third line). Then it saves and exits.
But even if you replace the quotes, there is still a problem in your command. From :h :bar
:
These commands see the '|' as their argument, and can therefore not be
followed by another Vim command:
...
:global
...
The bar is interpreted :g
as part of its argument, not as a command completion. In your case, this means that whenever it finds a line that starts with dog
, it deletes it and then immediately saves and exits. So, if there are multiple lines dog
, only the first one will be deleted because it :g
will be saved and completed after processing the first one.
You need to hide |wq
from :g
, either by zeroing out the global command inside the line and executing it with :execute
, or by moving wq
to another -c {cmd}
. In general, you can try:
vim -c 'exe "2,\$g/^dog/d" | wq' poo.txt
or
vim -c '2,$g/^dog/d' -c 'wq' poo.txt
or
vim -c '2,$g/^dog/d' -cx poo.txt
source to share