AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 679980
Accepted
Gabriel Staples
Gabriel Staples
Asked: 2021-12-03 22:15:54 +0800 CST2021-12-03 22:15:54 +0800 CST 2021-12-03 22:15:54 +0800 CST

如何从 ripgrep 输出的路径列表中单独处理每个路径

  • 772

我在 Linux Ubuntu 18.04 和 20.04 上。

Ripgrep ( rg) 可以输出包含匹配的文件的路径列表,如下所示:

# search only .txt files
rg 'my pattern to match' -g '*.txt' -l
# long form
rg 'my pattern to match' --glob '*.txt' --files-with-matches

输出将是:

path/to/file1.txt
path/to/file2.txt
path/to/file3.txt

等等

然后我想在每个路径上运行另一个命令,例如tree $(dirname $PATH),以获取包含匹配文件的目录中所有文件的列表。我怎样才能做到这一点?

我觉得xargs可能是答案的一部分?但是像这样开始的管道xargs似乎只处理最后打印的文件:

rg 'my pattern to match' -g '*.txt' -l | xargs -0 -I {} dirname {}

注意:如果您也可以演示,grep那么对于没有 的人也可能有用ripgrep,尽管 ripgrep非常易于安装。

参考:

  1. ripgrep:只打印匹配模式的文件名
grep shell
  • 2 2 个回答
  • 169 Views

2 个回答

  • Voted
  1. Stéphane Chazelas
    2021-12-03T23:49:29+08:002021-12-03T23:49:29+08:00

    在 GNU 系统上,可能是这样的:

    rg -g '*.txt' -l0 'my pattern to match' | # list files NUL-delimited
      xargs -r0 dirname -z -- |               # takes dirnames
      LC_ALL=C sort -zu |                     # remove duplicates
      xargs -r0 tree --
    

    请注意,如果两者都dir/file.txt匹配dir/subdir/file.txt,您最终会同时运行treeand dir,dir/subdir因此您将看到dir/subdir两次的内容。

    您有正确的想法,使用xargswhich 是将字节字符串转换为要传递给命令的参数列表的命令,并使用-0which 是传递任意参数列表的最可靠方法,但是:

    • xargs -0期望输入格式为参数列表由 NUL 字符(0 字节)分隔¹。您需要-0/--null选项才能rg以该格式打印文件列表。
    • GNUdirname每次调用可以处理多个参数,因此我们不使用-I{},而是将它们全部传递²。如果文件列表为空,我们还希望-r根本不调用,并且(也是 GNU 特定的)选项为自己打印以 NUL 分隔的目录。dirname-zdirnamedirname
    • 由于rg不会./为每个文件添加前缀,因此重要的是--对我们将文件列表作为参数传递给的命令使用选项分隔符,以避免-文件名中的前导 s 出现问题。

    简而言之,对于其值可以是任何非 NUL 字节序列(例如文件路径或任意命令参数)的列表,您希望使用 NUL 分隔的记录作为交换格式,以编程方式在工具之间传递列表,并且只保留人类格式向用户提供反馈的工具(这里是 的树状输出tree)。


    在非 GNU 系统上,但使用zshshell,您可以:

    files=( ${(0)"(rg -g '*.txt' -l0 'my pattern to match')"} )
    typeset -U unique_dirs=( $files:h )
    (( $#unique_dirs )) && tree -- $dirs
    

    或者一口气(假设至少有一个匹配的文件):

    tree -- ${(u)${(0)"$(rg -g '*.txt' -l0 'my pattern to match')"}:h}
    

    ( ufor unique) 是替换typeset -U. 0 参数扩展标志是我们告诉zsh在 NUL 上拆分的方式。或者,我们可以设置IFS=$'\0'并依赖分词(在不带引号的参数扩展时完成):

    IFS=$'\0'
    tree -- ${(u)$(rg -g '*.txt' -l0 'my pattern to match'):h}
    

    如果您既没有 GNU 实用程序也没有 GNU 实用程序zsh,您总是可以求助于perl:

    rg -g '*.txt' -l0 'my pattern to match' |
      perl -MFile::Basename -MList::Util=uniq  -0 -e '
        @dirs = uniq(map {dirname$_} <>);
        exec "tree", "--", @dirs if @dirs'
    

    ¹这是唯一一个不能出现在命令参数中的字符/字节值(因为参数在execve()系统调用中作为 NUL 分隔的字符串传递),但它可以出现在通过管道馈送的字节流中,所以它很简单以及在那里分离任意参数的明显方法。-0是 GNU 实现的非标准扩展xargs,但现在在许多其他实现中都可以找到它

    ² 或至少在一次调用中可以容纳的数量,dirname仅在需要时调用多次。

    • 3
  2. Best Answer
    Gabriel Staples
    2021-12-04T10:58:31+08:002021-12-04T10:58:31+08:00

    更新:新的最终答案:

    请注意,sort -zu对空分隔 ( -z) 列表中的重复项进行排序和删除。

    rg 'my pattern to match' -0 -g '*.txt' -l \
    | sort -zu \
    | xargs -0 -I{} -- dirname {} \
    | xargs -0 -I{} -- tree {}
    

    较早的答案详细信息:

    请参阅此答案下方的评论。我在这里的回答不如@Stéphane Chazelas 的其他回答那么可靠。

    我下面的答案最初不会正确处理任何带有空格或其他空格的文件名,也不会处理以破折号(-)开头的文件名。下面是我的回复评论:

    @StéphaneChazelas,您的所有评论都有意义。你的回答更有说服力。使用--null( -0) withrg和 withxargs肯定会更健壮。使用--也会。我想我并不太关心这些事情,因为我在 git repo 中运行此命令,其中没有一个文件中有空格,也没有以破折号 ( -) 开头。至于多个dirname&tree调用而不是一个具有多个路径的调用,我知道这一点,但也可以接受,部分原因是我想要一个答案,我可以轻松扩展并添加更多管道和命令来彻底改变它.

    所以,看看这两个答案。他在技术上更好,但就我的目的而言,我的现在“足够好”,并指出我在问题中的原始示例可能只需要极小的变化。前任:

    # I should have done this (add `-0` to `rg` and add `--` to `xargs`):
    rg 'my pattern to match' -0 -g '*.txt' -l | xargs -0 -I {} -- dirname {}
    
    # instead of this:
    rg 'my pattern to match' -g '*.txt' -l | xargs -0 -I {} dirname {}
    

    @Stéphane Chazelas的答案和我的问题下的评论(包括 ripgrep 的制造者本人的评论!)都很有用,并帮助我弄清楚了以下内容,我认为这是最简单和最好的答案,因为它是最简单的:

    from 的输出路径字符串rg不是以 null 结尾的字符串,因此请从命令中删除-0xargs(或者相反,将其添加到rg命令中)。而已!这现在有效:

    # THESE WORK to get the dirnames!
    # (`--null`/`-0` are removed from both `rg` and `xargs`)
    
    rg 'my pattern to match' -g '*.txt' -l | xargs -I {} dirname {}
    # OR (same thing--remove the space after `-I` is all):
    rg 'my pattern to match' -g '*.txt' -l | xargs -I{} dirname {}
    

    -0或者,您可以通过将或添加--null到命令来强制路径字符串以空值结尾rg,所以这也可以:

    # ALSO WORKS
    # (`--null`/`-0` are ADDED to both `rg` and `xargs`; note that for
    # both `rg` and `xargs`, `--null` is the long form of `-0`)
    
    rg 'my pattern to match' -g '*.txt' -l --null | xargs --null -I{} dirname {}
    

    现在,通过扩展,我们可以tree像这样传递所有路径:

    最终答案:

    rg 'my pattern to match' -0 -g '*.txt' -l \
    | xargs -0 -I{} -- dirname {} \
    | xargs -0 -I{} -- tree {}
    

    而已!我只需要在两个和所有调用中添加或减去 -0或添加或减去,以使它们保持一致并在解析多个路径时期望相同​​的轮廓符。--nullrgxargs

    但是,添加 -0or--null更好,因为它允许路径中包含空格或其他空格,并且添加--也很好,因为它允许路径以破折号 ( -) 开头。所以,这就是我在上面所做的。

    不过,请再次查看其他答案。它还排序、删除重复项和处理其他复杂问题。

    关键词:如何正确使用xargs;使用 xargs 解析 grep 或 ripgrep rg 输出路径

    • 0

相关问题

  • FreeBSD 的 sh:列出函数

  • grep --line-buffered 直到 X 行?

  • 有没有办法让 ls 只显示某些目录的隐藏文件?

  • grep -v grep 有什么作用

  • 如何将带有〜的路径保存到变量中?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve