web-dev-qa-db-ja.com

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

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

(注:それらはすべてtarballではない場合があり、一部はZipファイルです)

16
xenoterracide

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

このようにできるようです

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のどこにあるかはそれほど明確ではありません。うまくいけば、誰かがより良い答えを考え出すことができます。

1
xenoterracide

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

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

ただし、これをtarballでテストしなかった

0
Iggy Pop

多分私の答えは誰かのために役立ちます:

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

挑戦をありがとう、私は思いついた:

#!/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
0
Kyle Smith

インストール後p7Zip-*これを行うことができます:

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

圧縮ファイルが機能するリストが何であれ、最初のパイプの前にlsを使用する必要はありません。最後のlessは、圧縮されたアーカイブ内のリセットライフのパスのみを表示しますが、これの名前は表示しません。

0
Roberto Robert