Multiple :g and :v commands in one statement
I have this file
foo
foo bar
foo bar baz
bar baz
foo baz
baz bar
bar
baz
foo 42
foo bar 42 baz
baz 42
I want to
foo
and do NOT contain bar
foo
and do NOT contain bar
I read somewhere (can't find the link) that I have to use :exec with |
for this.
I tried the following, but it doesn't work
:exec "g/foo" # works
:exec "g/foo" | exec "g/bar" -- first returns lines with foo, then with bar
:exec "g/foo" | :g/bar -- same as above
And ofcourse if I cannot select a line, I cannot execute normal dd
on it.
Any ideas?
Edit
Note for the bounty:
I'm looking for a solution that uses proper :g and :v commands, and does not use regex hacks, as the conditions may not be the same (I can have 2 includes, 3 excludes).
Also note that the last 2 examples of things that don't work, they do work for just deleting the lines, but they return incorrect information when I run them without deleting (ie, viewing the selected lines) and they behave as mentioned above.
This might still be hackish to you, but you can write some vimscript to make a function and specialized command for this. For example:
command! -nargs=* -range=% G <line1>,<line2>call MultiG(<f-args>)
fun! MultiG(...) range
let pattern = ""
let command = ""
for i in a:000
if i[0] == "-"
let pattern .= "(.*<".strpart(i,1).">)@!"
elseif i[0] == "+"
let pattern .= "(.*<".strpart(i,1).">)@="
else
let command = i
endif
endfor
exe a:firstline.",".a:lastline."g/".pattern."/".command
endfun
This creates a command that allows you to automate the "regex hack". This way you could do
:G +foo -bar
to get all lines with foo and not bar. If an argument doesn't start with +
or -
then it is considered the command to add on to the end of the :g
command. So you could also do
:G d +foo -bar
to delete the lines, or even
:G norm foXp +two foos -bar
if you escape your spaces. It also takes a range like :1,3G +etc
, and you can use regex in the search terms but you must escape your spaces. Hope this helps.
I'm no vim wizard, but if all you want to do is "Delete lines which contain foo and do NOT contain bar" then this should do (I tried on your example file):
:v /bar/s/.*foo.*//
EDIT: actually this leaves empty lines behind. You probably want to add an optional newline to that second search pattern.
This is where regular expressions get a bit cumbersome. You need to use the zero width match (search_string)@=
. If you want to match a list of items in any order, the search_string
should start with .*
(so the match starts from the start of the line each time). To match a non-occurrence, use @!
instead.
I think these commands should do what you want (for clarity I am using #
as the delimiter, rather than the usual /
):
Select lines which contain foo and bar:
:g#(.*foo)@=(.*bar)@=
Select lines which contain foo, bar and baz
:g#(.*foo)@=(.*bar)@=(.*baz)@=
Select lines which contain foo and do NOT contain bar
:g#(.*foo)@=(.*bar)@!
Delete lines which contain foo and bar
:g#(.*foo)@=(.*bar)@=#d
Delete lines which contain foo and do NOT contain bar
:g#(.*foo)@=(.*bar)@!#d
上一篇: 复制并粘贴到vi中
下一篇: 多个:g和:v命令在一个语句中