如何递归地 grep 遍历压缩档案?

如何递归地 grep 遍历压缩档案?

我正在尝试找出哪些模块use Test::Version在cpan中。所以我用过minicpan来镜像它。我的问题是我需要遍历下载的档案,并 grep 档案中的文件。谁能告诉我我该怎么做?最好以某种方式告诉我存档中的哪个文件以及它位于哪一行。

(注意:它们并不都是 tarball,有些是 zip 文件)

答案1

好吧,让我们应用一下 Unix 哲学。这项任务的组成部分是什么?

  • 文本搜索:您需要一个工具来搜索文件中的文本,例如grep.
  • 递归:您需要一个工具来在目录树中查找文件,例如find.
  • 档案:您需要一个工具来阅读它们。

大多数 UNIX 程序都对文件进行操作。因此,为了轻松地操作存档组件,您需要将它们作为文件进行访问,换句话说,您需要将它们作为目录进行访问。

AVFS文件系统提供了文件系统的视图,其中每个存档文件都/path/to/foo.zip可以作为目录进行访问~/.avfs/path/to/foo/zip#。 AVFS 提供对最常见存档文件格式的只读访问。

mountavfs
find ~/.avfs"$PWD" \( -name '*.zip' -o -name '*.tar.gz' -o -name '*.tgz' \) \
     -exec sh -c '
                  find "$0#" -name "*.pm" -exec grep "$1" {\} +
                 ' {} 'Test::Version' \;
fusermount -u ~/.avfs   # optional

说明:

  • 挂载 AVFS 文件系统。
  • 在 中查找存档文件~/.avfs$PWD,这是当前目录的 AVFS 视图。
  • 对于每个存档,执行指定的 shell 片段(使用$0= 存档名称和$1= 搜索模式)。
  • $0#是档案的目录视图$0
  • {\}而不是在外部替代内部参数的{}情况下需要(有些这样做,有些不这样做)。find{}-exec ;
  • 可选:最后卸载 AVFS 文件系统。

或者在 zsh ≥4.3 中:

mountavfs
grep 'Test::Version' ~/.avfs$PWD/**/*.(tgz|tar.gz|zip)(e\''
     reply=($REPLY\#/**/*.pm(.N))
'\')

说明:

  • ~/.avfs$PWD/**/*.(tgz|tar.gz|zip)匹配当前目录及其子目录的 AVFS 视图中的档案。
  • PATTERN(e\''CODE'\')将 CODE 应用于 PATTERN 的每个匹配项。匹配文件的名称位于$REPLY.设置reply数组会将匹配项转换为名称列表。
  • $REPLY\#是档案的目录视图。
  • $REPLY\#/**/*.pm匹配.pm存档中的文件。
  • N如果没有匹配项,则 glob 限定符会使模式扩展为空列表。

答案2

看来我可以这样做

find authors/ -type f -exec zgrep "Test::Version" '{}' +  

然而,这给出了如下结果:

authors/id/J/JO/JONASBN/Module-Info-File-0.11.tar.gz:Binary file (standard input) matches

这对于 tarball 中的位置并不是很具体。希望有人能给出更好的答案。

答案3

乌格勒普使用选项递归搜索压缩文件 (gz/Z/bz2/lzma/xz/lz4/zstd) 和存档 (cpio/tar/pax/zip) -z。选项-z --zmax=2搜索嵌入在压缩文件和档案中的压缩文件和档案(因此 zmax=2 级)。

答案4

也许我的回答对某人有帮助:

#!/bin/bash

findpath=$(echo $1 | sed -r 's|(.*[^/]$)|\1/|')

# tarballs to check in
find $findpath -type f | while read tarball; do

    # get list of files in tarball (not dirs ending in /):
    if [ -n "$(file --mime-type $tarball | grep -e "application/jar")" ]; then

        jar tf $tarball | grep -v '/$' | while read file; do
            # get contents of file and look for string
            grepout=$(unzip -q -c $tarball $file | grep $3 -e "$2")

            if [ -n "$grepout" ]; then
                echo "*** $tarball has matching file ($file):"
                echo $grepout
            fi

        done

    elif tar -tf $tarball 2>/dev/null; then

        tar -tf $tarball | grep -v '/$' | while read file; do
            # get contents of file and look for string
            grepout=$(unzip -q -c $tarball $file | grep $3 -e "$2")

            if [ -n "$grepout" ]; then
                echo "*** $tarball has matching file ($file):"
                echo $grepout
            fi

        done

    else
        file=""
        grepout=$(grep $3 -e "$2" $tarball)

        if [ -n "$grepout" ]; then
            echo "*** $tarball has matching:"
            echo $grepout
        fi

    fi

done

相关内容