irritable_phd_syndrome
irritable_phd_syndrome

Reputation: 5067

Differences in running vim via command line vs. running it in the vim editor

I am trying to process a series of files. I have noticed that there are discrepancies in running a particular command from the command line (i.e. ex mode). E.g.

$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 appears that 2,$g/^dog/d|wq has deleted the lines with red and dog. This confuses me because the command should : start on line 2 (going to EOF) and delete all lines beginning with dog. In this instance, I'd expect the output to be:

$ 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 cause of the discrepancy between the vim -c version and the vim version of running this command?

Upvotes: 4

Views: 605

Answers (1)

user852573
user852573

Reputation: 1750

I think you need to replace the double quotes with single quotes to prevent your shell from expanding $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 was an environment variable. But it's probably not defined, thus expands into an empty string. So, even though you've typed:

vim -c "2,$g/^dog/d|wq" poo.txt

Vim doesn't receive the command:

2,$g/^dog/d|wq

... but:

2,/^dog/d|wq

This command deletes all the lines from the one whose address is 2, to the next one which starts with dog (in your case it's the 3rd line). Then, it saves and quit.

But even if you replace the quotes, there's 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 by :g as a part of its argument, not as a command termination. In your case, it means that whenever it finds a line starting with dog, it will delete it, then immediately save and quit. So, if there are several dog lines, only the first one will be deleted, because :g will have saved and quit after processing the 1st one.

You need to hide |wq from :g, either by wrapping the global command inside a string and executing it with :execute, or by moving wq in another -c {cmd}. All in all, you could 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

Upvotes: 3

Related Questions