如何通过压缩档案递归grep?


16

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

(注意:它们不是全部的tarball,有些不是zip文件)

Answers:


18

好的,让我们应用Unix哲学。此任务的组成部分是什么?

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

大多数Unix程序对文件进行操作。因此,要在存档组件上轻松操作,您需要以文件形式访问它们,换句话说,您需要以目录形式访问它们。

动静脉瘘文件系统呈现,每一个存档文件中的文件系统的观点/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预选赛中,使图案水珠扩大到一个空列表,如果没有匹配。

这就产生了另一个
令人费解

@xenoterracide:怎么了?使用AVFS,您只有一个安装点(~/.avfs),并且对每个档案的访问是自动的(~/.avfs/path/to/archive.zip\#是AVFS文件系统上的普通目录,而不是安装点)。当然,您访问的每个档案都对性能造成一点影响,但这是问题的内在原因。
吉尔(Gilles)'所以

@gilles仅是这样一个事实,我现在必须首先弄清楚如何安装它们,这似乎是一个坏主意,最好在我搜索它们时卸载并卸载。
xenoterracide

@xenoterracide:再说一次:不,您不需要单独安装它们。完整的工作流程(除了安装AVFS之外,如果需要的话)在我的代码段中。
吉尔(Gilles)'所以

@gilles好,我必须对此做个深入的研究……因为我find: missing argument to 从zsh中获得了-exec'`和很多内容zsh: Input/output error: Data-Maker-0.27
xenoterracide

0

看来我可以这样

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中的位置不太相关。希望有人能提出更好的答案。


0

感谢您的挑战,我想到了:

#!/bin/bash
#

# tarballs to check in
find authors/ -type f | while read tarball; do

    # get list of files in tarball (not dirs ending in /):
    tar tzf $tarball | grep -v '/$' | while read file; do       

        # get contents of file and look for string
        tar -Ozxf conform.tar.gz $file | grep -q 'Text::Version' && echo "Tar ($tarball) has matching File ($file)"

    done

done

刚看到您的行号要求。这可能可以与grep -n和awk的某种组合一起使用以捕获行号。列出文件名不能像grep -H那样简单,因为它始终是stdin,因此可能需要更多行。
凯尔·史密斯

在我的系统上运行时出现错误,无限重复:tar (child): conform.tar.gz: Cannot open: No such file or directory tar (child): Error is not recoverable: exiting now tar: Child returned status 2 tar: Error is not recoverable: exiting now
xenoterracide

当我第一次发布此内容时,我也没有意识到cpan上的某些存档是zip文件。
xenoterracide

嗯,我仅使用 .tar.gz文件的结构进行了测试-可以使其更健壮,以便根据文件类型采取适当的措施,但这应该是一个不错的起点。
凯尔·史密斯

0

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

#!/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

0

安装后,p7zip-*您可以执行以下操作:

ls | xargs -I {} 7z l {} | grep whatever | less

您不必ls在第一个管道之前使用压缩列表即可使用的任何列表。最后less仅显示压缩存档中列表列表生命的PATH,但不显示其名称。


0

使用find查找所有必需的文件,并使用zgrep查找压缩文件:

find <folder> -type f -name "<search criteria[*gz,*bz...]>" -execdir zgrep -in "<grep expression>" '{}' ';'

虽然没有在tarball上测试

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.