【问题标题】:How to pipe list of files returned by find command to cat to view all the files如何将 find 命令返回的文件列表通过管道传输到 cat 以查看所有文件
【发布时间】:2010-10-26 05:53:39
【问题描述】:

我正在执行find,然后获取文件列表。如何将其通过管道传输到另一个实用程序,例如 cat(以便 cat 显示所有这些文件的内容),并且基本上需要从这些文件中获取 grep 的内容。

【问题讨论】:

    标签: unix find pipe


    【解决方案1】:
    1. 管道到另一个进程(尽管这不会完成你所说的你正在尝试做的事情):

      command1 | command2
      

      这会将command1的输出作为command2的输入发送

    2. -execfind 上(这将做你想做的事——但特定于find

      find . -name '*.foo' -exec cat {} \;
      

      find-exec 之间的所有内容都是您已经使用的查找谓词。{} 会将您找到的特定文件替换为命令(在这种情况下为cat {});\; 是结束-exec 命令。)

    3. 将一个进程的输出作为命令行参数发送到另一个进程

      command2 `command1`
      

      例如:

      cat `find . -name '*.foo' -print`
      

      (注意这些是反引号而不是常规引号(在我键盘上的波浪号 ~ 下)。) 这会将command1 的输出作为命令行参数发送到command2。请注意,包含空格(换行符等)的文件名将被分解为单独的参数。

    【讨论】:

    • cat find -name '*.foo' -print 对我很有用...谢谢
    • 反引号效果很好并且更通用,您也可以使用它从文件中查找文件列表。
    • 请注意,find 的现代版本允许您编写:find . -name '*.foo' -exec cat {} +,其中+ 表示find 应该将尽可能多的文件名分组到单个命令调用中。这非常有用(它处理文件名中的空格等,而不诉诸-print0xargs -0)。
    • 未提及:find . -name '*.foo' | xargs cat
    • 只是添加@stewSquared 的答案:要查找包含特定字符串的文件中的所有行,请执行find . -name '*.foo' | xargs cat | grep string
    【解决方案2】:

    现代版

    POSIX 2008 将+ 标记添加到find,这意味着它现在会自动将尽可能多的文件分组到单个命令执行中,这与xargs 非常相似,但具有许多优点:

    1. 您不必担心文件名中的奇数字符。
    2. 您不必担心使用零文件名调用的命令。

    文件名问题是xargs 没有-0 选项的问题,而“即使文件名为零也运行”问题是有或没有-0 选项的问题——但GNU xargs-r--no-run-if-empty 选项可防止这种情况发生。此外,此符号减少了进程的数量,而不是您可能会衡量性能差异。因此,您可以明智地写:

    find . -exec grep something {} +
    

    经典版

    find . -print | xargs grep something
    

    如果您在 Linux 上或拥有 GNU findxargs 命令,则使用 -print0find-0xargs 来处理包含空格和其他奇怪球的文件名字符。

    find . -print0 | xargs -0 grep something
    

    调整来自grep 的结果

    如果您不想要文件名(只是文本),那么在grep 中添加一个适当的选项(通常是-h 以抑制“标题”)。为了绝对保证文件名是grep打印出来的(即使只找到一个文件,或者grep最后一次调用只给了1个文件名),那么在xargs命令行中添加/dev/null,这样总会有至少两个文件名。

    【讨论】:

    • 像我一样迷茫的,注意这种方式会先给出find的所有输出,再给出xargs grep something的输出。
    • @EricHu:我看得出来你很困惑,但它并没有像你说的那样做,至少在我所知道的任何基于 Unix 的系统上都没有。 find 的输出通过管道传送到xargs 的标准输入。 xargs 程序读取它的标准输入,在空白处分割输入(空格、换行符、制表符等)并将一些单词附加到命令grep something 并执行命令行。 xargs 然后继续读取输入并执行命令,直到输入用完。 xargs 尽可能频繁地运行grep 命令,以获取它所提供的输入(在此示例中来自find)。
    • 啊我的错,这是使用 grep 在每个匹配的文件中搜索。我想用 grep 简单地过滤 find 的输出
    • 在所有行为良好的命令上,错误都会出现标准错误(文件描述符 2)。将 stderr 重定向到 /dev/null 会丢失错误消息。
    • 这还有一个好处是它可以更好地处理文件路径中的空格。甚至 'sed'ing " " -> "\" 用 ` 打破它,但使用 xargs 它可以完美地工作
    【解决方案3】:

    有几种方法可以将find 命令返回的文件列表传递给cat 命令,但从技术上讲,并非全部都使用管道,实际上也没有一种方法直接通过管道传递给cat

    1. 最简单的是使用反引号(`):

      cat `find [whatever]`
      

      这将获取find 的输出并将其有效地放置在cat 的命令行中。如果find 的输出过多(命令行无法容纳)或输出包含特殊字符(如空格),则此方法效果不佳。

    2. 在某些 shell 中,包括 bash,可以使用 $() 代替反引号:

      cat $(find [whatever])
      

      这不太便携,但可以嵌套。除此之外,它的注意事项与反引号几乎相同。

    3. 因为对找到的文件运行其他命令是 find 的常见用途,所以 find 有一个 -exec 操作,它为找到的每个文件执行一个命令:

      find [whatever] -exec cat {} \;
      

      {} 是文件名的占位符,\; 标志着命令的结束(-exec 之后可能还有其他操作。)

      这将为每个文件运行一次cat,而不是运行cat 的单个实例,将多个文件名传递给它,这可能效率低下,并且可能没有你想要的某些命令的行为(尽管它对@987654340 很好@)。语法也很难输入——你需要转义分号,因为分号对 shell 来说是特殊的!

    4. find 的某些版本(尤其是 GNU 版本)允许您将 ; 替换为 + 以使用 -exec 的附加模式来运行更少的 cat 实例:

      find [whatever] -exec cat {} +
      

      这会将多个文件名传递给cat 的每次调用,这样会更有效率。

      请注意,这保证使用单个调用,但是。如果命令行太长,那么参数将分布在cat 的多个调用中。对于cat,这可能没什么大不了的,但对于其他一些命令,这可能会以不受欢迎的方式改变行为。在 Linux 系统上,命令行长度限制非常大,因此与其他一些操作系统相比,拆分为多个调用非常罕见。

    5. 经典/便携的方法是使用xargs:

      find [whatever] | xargs cat
      

      xargs 运行指定的命令(在本例中为cat),并根据从标准输入中读取的内容添加参数。就像-exec+ 一样,这将在必要时分解命令行。也就是说,如果find 产生过多的输出,它将运行cat 多次。正如前面关于-exec 的部分所述,在某些命令中,这种拆分可能会导致不同的行为。请注意,像这样使用 xargs 在文件名中存在空格问题,因为 xargs 只是使用空格作为分隔符。

    6. 最健壮、便携、高效的方法也是使用xargs

      find [whatever] -print0 | xargs -0 cat
      

      -print0 标志告诉find 在文件名之间使用\0(空字符)分隔符,-0 标志告诉xargs 期待这些\0 分隔符。这与-exec...+ 方法的行为几乎相同,但更便携(但不幸的是更冗长)。

    【讨论】:

    • 反引号方法很棒,因为它也适用于ls等其他命令。
    • @Martin Braun using $() 也适用于find 以外的命令。
    • 谢谢,很高兴知道,在 (1) 之后我有点停止阅读,因为它满足我的需要,因为我不处理空格等特殊字符。
    【解决方案4】:

    为了实现这一点(使用 bash),我将执行以下操作:

    cat $(find . -name '*.foo')
    

    这被称为“命令替换”,默认情况下会去除换行符,非常方便!

    更多信息here

    【讨论】:

      【解决方案5】:

      对我来说听起来像是一个 shell 脚本的工作:

      for file in 'find -name *.xml'
      do
         grep 'hello' file
      done
      

      或者类似的东西

      【讨论】:

      • 这是对问题的有效但不一定是最佳的答案。
      • ...是的,但如果您想要一个包含文件名的大文件,那就太好了。
      • 我最喜欢这个。像这样的循环块为做其他事情留下了空间。
      【解决方案6】:

      这是我查找包含一些我感兴趣的内容的文件名的方法,只需一个 bash 行就可以很好地处理文件名中的空格:

      find . -name \*.xml | while read i; do grep '<?xml' "$i" >/dev/null; [ $? == 0 ] && echo $i; done
      

      【讨论】:

        【解决方案7】:

        这是我的一般用途:

        grep YOURSTRING `find .`
        

        它将打印文件名

        【讨论】:

          【解决方案8】:

          我使用这样的东西:

          find . -name <filename> -print0 | xargs -0 cat | grep <word2search4>
          

          “find”的“-print0”参数和“xargs”的“-0”参数需要正确处理文件路径/名称中的空格。

          【讨论】:

            【解决方案9】:

            find 命令有一个 -exec 参数,你可以用它来做这样的事情,你可以直接使用它来执行 grep。

            例如(from here, other good examples at this page):

            find . -exec grep "www.athabasca" '{}' \; -print 
            

            【讨论】:

              【解决方案10】:

              在 bash 中,以下是合适的:

              find /dir -type f -print0 | xargs -0i cat {} | grep whatever
              

              这将找到/dir 目录中的所有文件,并将文件名安全地通过管道传输到xargs,这将安全地驱动grep

              如果/dir 中有数千个文件,则跳过xargs 不是一个好主意; cat 将因参数列表长度过长而中断。 xargs 将为您解决所有问题。

              find-print0 参数与 xargs-0 参数相结合,可以正确处理带有空格的文件名。 xargs-i 参数允许您在 cat 命令行中需要的位置插入文件名。括号替换为从find 传递到cat 命令的文件名。

              【讨论】:

                【解决方案11】:

                这对我有用

                find _CACHE_* | while read line; do
                    cat "$line" | grep "something"
                done
                

                【讨论】:

                  【解决方案12】:

                  使用ggrep

                  ggrep -H -R -I "mysearchstring" *
                  

                  在 unix 中搜索包含位于当前目录或子目录中的文本的文件

                  【讨论】:

                    【解决方案13】:

                    这将仅递归打印文件的名称和内容..

                    find . -type f -printf '\n\n%p:\n' -exec cat {} \;
                    

                    编辑(改进版): 这将仅以递归方式打印文本(ascii)文件的名称和内容..

                    find . -type f -exec grep -Iq . {} \; -print | xargs awk 'FNR==1{print FILENAME ":" $0; }'
                    

                    再试一次

                    find . -type f -exec grep -Iq . {} \; -printf "\n%p:" -exec cat {} \;
                    

                    【讨论】:

                      【解决方案14】:

                      您是否要在文件中查找文本?你可以简单地使用 grep...

                      grep searchterm *
                      

                      【讨论】:

                        【解决方案15】:

                        列出和查看服务器上目录 /ghi 和 /jkl 中所有 abc.def 文件的内容

                        find /ghi /jkl -type f -name abc.def 2> /dev/null -exec ls {} \; -exec cat {} \;
                        

                        要列出带有注释条目的 abc.def 文件并显示,请参见目录 /ghi 和 /jkl 中的这些条目

                        find /ghi /jkl -type f -name abc.def 2> /dev/null -exec grep -H ^# {} \;
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 2020-02-16
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2021-08-24
                          • 2011-06-28
                          • 1970-01-01
                          相关资源
                          最近更新 更多