圧縮アーカイブを再帰的にgrepする方法は?

圧縮アーカイブを再帰的にgrepする方法は?

どのモジュールなのか調べてみます。use Test::Versioncpanから。だから私は使用しましたminicpanそれを反映しています。私の問題は、ダウンロードしたアーカイブを繰り返し、アーカイブ内のファイルをgrepする必要があることです。どうすればいいのか教えてもらえますか?アーカイブ内のどのファイルがどの行にあるのかどうかを知らせる方が良いでしょう。

(注:すべてタールボールではなく、一部は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ビューインでアーカイブファイルを見つけます。
  • 各アーカイブに対して指定されたシェルフラグメントを実行します($0=archive名と$1=searchパターンを使用)。
  • $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一致するものがない場合、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

これはタールボールの位置にあまり具体的ではありません。誰かがより良い答えを与えることを願っています。

答え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

関連情報