圧縮されたアーカイブを再帰的にgrepするにはどうすればよいですか?


16

私はuse Test::Versioncpanのどのモジュールを見つけようとしています。だから私はminicpanそれをミラーリングするために使用しました。私の問題は、ダウンロードされたアーカイブを反復処理し、アーカイブ内のファイルをgrepする必要があることです。誰も私にこれをどうやってやるか教えてもらえますか?できれば、アーカイブ内のファイルとその行を教えてくれる方法で。

(注:それらはすべてtarballであるわけではなく、一部はzipファイルです)

回答:


18

OK、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ビューです。
  • 各アーカイブに対して、指定されたシェルスニペットを実行します($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'\')PATTERNの各一致にCODEを適用します。一致したファイルの名前はです$REPLYreply配列を設定すると、一致が名前のリストに変わります。
  • $REPLY\# アーカイブのディレクトリビューです。
  • $REPLY\#/**/*.pm.pmアーカイブ内のファイルと一致します。
  • Nグロブ修飾子は一致しない場合、パターンは空のリストに展開されます。

これは、すべてのアーカイブをマウントしてからアンマウントする必要があるという別の問題を引き起こします。問題の一部は、検索する必要がある22kのアーカイブがあることです
-xenoterracide

@xenoterracide:それは問題ですか?AVFSでは、単一のマウントポイント(~/.avfs)があり、各アーカイブへのアクセスは自動的に行われます(~/.avfs/path/to/archive.zip\#マウントポイントではなく、AVFSファイルシステム上の通常のディレクトリです)。確かに、アクセスする各アーカイブはパフォーマンスに少し影響を与えますが、それは問題に固有のものです。
ジル 'SO-悪であるのをやめる'

@gillesは、今私が最初にそれらをマウントする方法を理解しなければならないという事実だけです。これは少し悪いアイデアのように見えますが、検索後にマウントしてマウント解除する方が良いでしょう。
xenoterracide

@xenoterracide:繰り返します。いいえ、個別にマウントする必要はありません。完全なワークフロー(必要に応じてAVFSをインストールすることを除く)は、私のコードスニペットにあります。
ジル「SO-悪であるのをやめる」

@gillesよく私はこれを少し掘り下げなければなりません... find: missing argument to -exec'`とzshからこれの多くを得るため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のようにファイル名をリストするのは簡単ではありません。ファイル名は常に標準入力なので、より多くの行が必要になる場合があります。
カイルスミス

システムで実行するとエラーが発生し、無限に繰り返されます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は、圧縮アーカイブ内のリストセットライフのパスのみが表示されますが、この名前は表示されません。


0

findを使用してすべての必要なファイルを見つけ、そのzgrepを使用して圧縮ファイルを調べます。

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

ただし、これをtarballでテストしませんでした

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.