从 Vim 内部执行 Greping(使用管道)

发布于 2024-11-07 19:37:15 字数 216 浏览 0 评论 0原文

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

:grep -nHr abc * | grep -v xyz

不幸的是,vim 不喜欢“管道”并且命令失败。在 vim 中执行此操作的最佳方法是什么?

I want to create a 'quickfix' list (see :help quickfix) with all files that contain lines with "abc" but not "xyz". I was hoping I could run the following vim ex command:

:grep -nHr abc * | grep -v xyz

Unfortunately, vim doesn't like the "pipe" and the command fails. What is the best way to do this from within vim?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

转瞬即逝 2024-11-14 19:37:15

很多年过去了,但我找到了更直接的替代方案。 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 *')

It's many years later, but I found more direct alternative. cexpr command in vim. It pretty much implements the answers from @jwd and @skeept, and is a bit more flexible because it accepts a list.

Below is an example use of my own which uses pipes. I prefix all my questions in my work notes with Q: to find them quickly. I wanted to use quickfix list and vim to browse through questions, viewing the most recent first.

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

Relevant excerpt from the vim help.

: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 *')

清泪尽 2024-11-14 19:37:15

出于某种原因,我不能放过这个!

怎么样使用 :!grep ... > filename 后跟 :cf filename,这将以快速修复列表的形式打开输出。

For some reason I can't leave this one alone!

How about use :!grep ... > filename followed by :cf filename, which will open the output as a quickfix list.

眼角的笑意。 2024-11-14 19:37:15

我刚刚弄清楚如何转义 :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 后,在拆分窗口中打开一个缓冲区,其中包含快速列表本身:

:cope[Enter]

要充分利用此功能,请了解拆分窗口,特别是使用 Ctrl-W 在拆分窗口之间导航Ctrl-W 和其他 Ctrl-W 命令。

在快速修复结果窗口中,您可以通过以普通方式搜索来“优化搜索”,就像在任何缓冲区中一样。无论您导航到哪一行,您只需按该行上的 Enter 即可跳转到其他窗口中的该快速列表项。光标自动转到该窗口:要返回快速列表结果以搜索其他内容,请使用 Ctrl-W Ctrl-W。

您还可以通过从 :cope 缓冲区中删除不需要的行来修剪快速列表结果。默认情况下,缓冲区是不可修改的,因此首先您必须确保光标位于该窗口中,然后:

 :set modifiable

然后您可以执行诸如

 :g/xyz/d

删除所有包含 xyz 的结果之类的操作。现在只有剩下的行才是快速修复列表的一部分。

I just figured out how to escape :grepprg to use a pipe.

In my case, my :grepprg is based on the lid utility from GNU Idutils. I want the output of the lid program to be sorted. this is because when I use a pattern, lid finds matches out of order. I want to look for a pattern like, say, pthread.*lock and step through the matches in order to follow lock nesting, and not jump around between files in a way that follows the internal order of the ID database generated by mkid, which interleaves the matches from different files.

The pipe requires double escaping. It seems that Vim ends up processing the value of grepprg as command material. If you escape the pipe just once, it is interpreted as Vim syntax.

So what I have now in my .vimrc is this:

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

The pipe is escaped as \\\|: an escaped backslash and an escaped pipe to produce \|, which undergoes one more round of processing to end up with |.

Based on this example, it is possible to customize your grep command to include arbitrary Unix plumbing.


If you just want to trim the results of a quicklist, or to search within the results, there is an interactive way.

After doing the :grep, open a buffer in a split window which contains the quicklist itself:

:cope[Enter]

To make the best use of this, learn about split windows and in particular, navigation between split windows using Ctrl-W Ctrl-W, and other Ctrl-W commands.

In the quickfix result window, you can "refine your search" by searching in the ordinary way, like in any buffer. Whatever line you navigate to, you can just hit Enter on that line to jump to that quicklist item in your other window. The cursor automatically goes to that window: to return to the quicklist results to search for something else, use Ctrl-W Ctrl-W.

You can also trim the quicklist results simply by deleting unwanted lines from the :cope buffer. The buffer is unmodifiable by default, so first you have to make sure your cursor is in that window and then:

 :set modifiable

Then you can do something like

 :g/xyz/d

to delete all results that contain xyz. Only the lines which remain are now part of the quickfix list.

踏雪无痕 2024-11-14 19:37:15

你可以分两步完成:

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

如果你经常改变模式,你可能可以使用一个函数来包装它
以下并不完美,但有效:

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”
(您可能需要键入以清除屏幕)。

you can do it in two steps:

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

if you change frequently of patterns yo probably can use a function to wrap this
the following is not perfect, but works:

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

and then call it using:

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

it seems to work for me but I also get an error message "trailin charathers"
(you may need to type to clear the screen).

凌乱心跳 2024-11-14 19:37:15

您可以设置 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& 恢复为默认命令。

You can set grepprg, which defines what command Vim uses to execute :grep. It can contain pipes, though it's difficult to get the escaping correct using :set. If you use :let instead, you can pass an expression. Using a string literal for that expression provides simpler escaping rules, so you can use a more readable value. Here's an example that filters out unwanted files first, then offers multiline matching with 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 '

All the backslashes are passed to the shell as-is with the exception of those that immediately precede %, as they are consumed when preventing expansion into filenames and paths.

Of course, that would affect all your :greps but you can revert to the default command with :set gp&.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文