从Vim内部Greping(使用管道)

9o685dep  于 2023-10-20  发布在  其他
关注(0)|答案(5)|浏览(122)

我想创建一个'quickfix'列表(参见:help quickfix),其中包含所有包含“abc”但不包含“xyz”的行的文件。我希望我可以运行以下Vim ex命令:

:grep -nHr abc * | grep -v xyz

不幸的是,Vim不喜欢“管道”,命令失败。在Vim中实现这一点的最佳方法是什么?

yjghlzjz

yjghlzjz1#

出于某种原因,我不能离开这一个单独!
如何使用:!grep ... > filename后跟:cf filename,这将以quickfix列表的形式打开输出。

5ssjco0h

5ssjco0h2#

多年后的今天,我找到了更直接的替代方法。Vim中的cexpr命令。它几乎实现了来自@jwd和@skeept的答案,并且更灵活一些,因为它接受一个列表。
下面是我自己使用管道的一个例子。我在工作笔记中的所有问题前面都加上了Q:,以便快速找到它们。我想使用quickfix list和Vim浏览问题,首先查看最近的问题。

:cexpr system("grep -R --line-number Q: --exclude '*~' ~/_Notes/work-log/ \| sort \| tac")

Vim帮助中的相关摘录。

:cex[pr][!] {expr}  Create a quickfix list using the result of {expr} and
            jump to the first error.
            If {expr} is a String, then each new-line terminated
            line in the String is processed using the global value
            of 'errorformat' and the result is added to the
            quickfix list.
            If {expr} is a List, then each String item in the list
            is processed and added to the quickfix list.  Non
            String items in the List are ignored.
            See |:cc| for [!].
            Examples: >
                :cexpr system('grep -n xyz *')
jmp7cifd

jmp7cifd3#

我刚刚弄明白了如何使用管道来转义:grepprg
在我的例子中,我的:grepprg基于GNU Idutils的lid实用程序。我希望lid程序的输出被排序。这是因为当我使用模式时,lid会乱序查找匹配项。我想寻找一个模式,比如说,pthread.*lock,并逐步通过匹配,以遵循锁嵌套,而不是以遵循mkid生成的ID数据库的内部顺序的方式在文件之间跳转,这会交错来自不同文件的匹配。
管道需要双重转义。看起来Vim最终处理grepprg的值作为命令材料。如果只转义管道一次,它将被解释为Vim语法。
所以我现在在我的.vimrc中有:

:set grepprg=lid\ --substring\ --result=grep\ '\\<$*\\>'\ \\\|\ sort

管道被转义为\\\|:一个转义反斜杠和一个转义管道生成\|,它再经过一轮处理,最终得到|
基于这个示例,可以自定义grep命令以包含任意Unix管道。
如果你只是想修剪快速列表的结果,或者在结果中搜索,有一种交互式的方式。
完成:grep之后,在一个包含quicklist本身的分割窗口中打开一个缓冲区:

:cope[Enter]

要充分利用这一点,请了解拆分窗口,特别是使用Ctrl-W Ctrl-W和其他Ctrl-W命令在拆分窗口之间导航。
在quickfix结果窗口中,您可以通过普通方式搜索来“细化搜索”,就像在任何缓冲区中一样。无论你导航到哪一行,你都可以在那一行点击Enter跳转到另一个窗口中的快速列表项。光标自动转到该窗口:要返回快速列表结果以搜索其他内容,请使用Ctrl-W Ctrl-W。
您还可以通过从:cope缓冲区中删除不需要的行来修剪快速列表结果。默认情况下,缓冲区是不可修改的,所以首先你必须确保你的光标在该窗口中,然后:

:set modifiable

然后你可以做一些事情,

:g/xyz/d

删除所有包含xyz的结果。现在只有剩下的行是quickfix列表的一部分。

7vux5j2d

7vux5j2d4#

你可以分两步来做:

:!(grep -nHr abc * | grep -v xyz >| qf.txt)
:cfile qf.txt | copen

如果你经常改变模式,你可能可以使用一个函数来 Package 它,下面的方法并不完美,但可以工作:

fu! Mygrep(pat1, pat2)
  let cmd = "silent !(grep -nHr " . a:pat1 . " * | grep -v " . a:pat2 . " >| qf.txt)"
  silent exec cmd
  cfile qf.txt
  copen 
endfunction

然后调用它使用:

:call Mygrep("abc", "xyz")

它似乎对我有效,但我也得到一个错误信息“trailin charathers”(您可能需要键入以清除屏幕)。

hgncfbus

hgncfbus5#

您可以设置grepprg,它定义了Vim使用什么命令来执行:grep。它可以包含管道,尽管使用:set很难获得正确的转义。如果使用:let,则可以传递一个表达式。对该表达式使用字符串文字提供了更简单的转义规则,因此可以使用可读性更强的值。这里有一个例子,它首先过滤掉不需要的文件,然后使用PCRE提供多行匹配:

let &gp='find . \! \( \( -path ./node_modules -o -path ./vendor -o -name '*.tags' \) -prune \) -type f -printf \%P\\0 | sort -z | xargs -0r pcre2grep -nIM '

所有反斜杠都按原样传递给shell,除了紧接在%之前的反斜杠,因为它们在防止扩展到文件名和路径时被消耗。
当然,这会影响你的所有:grep,但是你可以用:set gp&恢复到默认命令。

相关问题