63

ダースのファイル .tar.gz からパターンを grep しようとしていますが、非常に遅いです

使用しています

tar -ztf file.tar.gz | while read FILENAME
do
        if tar -zxf file.tar.gz "$FILENAME" -O | grep "string" > /dev/null
        then
                echo "$FILENAME contains string"
        fi
done
4

9 に答える 9

125

持っていればzgrep使えます

zgrep -a string file.tar.gz
于 2013-06-05T13:06:21.653 に答える
33

この--to-commandオプションを使用して、ファイルを任意のスクリプトにパイプできます。これを使用すると、アーカイブを 1 回のパスで (一時ファイルなしで) 処理できます。この質問マニュアルも参照してください。上記の情報があれば、次のようなことを試すことができます。

$ tar xf file.tar.gz --to-command "awk '/bar/ { print ENVIRON[\"TAR_FILENAME\"]; exit }'"
bfe2/.bferc
bfe2/CHANGELOG
bfe2/README.bferc
于 2012-12-21T15:32:48.057 に答える
10

この質問は4年前のものであることは知っていますが、いくつかの異なるオプションがあります:

オプション 1: 使用tar --to-command grep

次の行は を検索しexample.tgzますPATTERN。これは @Jester の例に似ていますが、彼のパターン マッチングを機能させることができませんでした。

tar xzf example.tgz --to-command 'grep --label="$TAR_FILENAME" -H PATTERN ; true'

オプション 2: 使用tar -tzf

2 番目のオプションは、 を使用tar -tzfしてファイルを一覧表示してから、を使用して調べますgrep。何度も使用する関数を作成できます。

targrep () {
    for i in $(tar -tzf "$1"); do
        results=$(tar -Oxzf "$1" "$i" | grep --label="$i" -H "$2")
        echo "$results"
    done
}

使用法:

targrep example.tar.gz "pattern"
于 2017-02-15T19:05:15.600 に答える
4

これが本当に遅い場合は、大きなアーカイブ ファイルを扱っていると思われます。grep では、一度解凍してファイル リストを抽出し、N 回 (N はアーカイブ内のファイル数) 解凍します。すべての解凍に加えて、各ファイルを抽出するために毎回かなりの量をアーカイブにスキャンする必要があります。の最大の欠点の1 つはtar、冒頭に目次がないことです。アーカイブ内のすべてのファイルに関する情報を取得し、ファイルのその部分のみを読み取る効率的な方法はありません。基本的に、毎回抽出するものまですべてのファイルを読み取る必要があります。ファイル名の場所にすぐにジャンプすることはできません。

これを高速化するためにできる最も簡単な方法は、最初にファイルを解凍し ( gunzip file.tar.gz)、次に.tarファイルで作業することです。それだけで十分に役立つかもしれません。ただし、アーカイブ全体を N 回ループします。

これを本当に効率的にしたい場合、唯一のオプションは、アーカイブを処理する前にアーカイブ内のすべてを完全に抽出することです。問題は速度であるため、これは最初に抽出したくない巨大なファイルであると思われますが、可能であれば、これにより速度が大幅に向上します。

tar zxf file.tar.gz
for f in hopefullySomeSubdir/*; do
  grep -l "string" $f
done

grep -l一致するファイルの名前を出力し、最初の一致後に終了し、一致がない場合は黙っていることに注意してください。それだけで、コマンドの grep 部分が高速化されるため、アーカイブ全体を抽出するスペースがない場合でもgrep -l役立ちます。ファイルが巨大な場合、それは大いに役立ちます。

于 2012-12-21T02:24:11.197 に答える
3

手始めに、複数のプロセスを開始できます。

tar -ztf file.tar.gz | while read FILENAME
do
        (if tar -zxf file.tar.gz "$FILENAME" -O | grep -l "string"
        then
                echo "$FILENAME contains string"
        fi) &
done

( ... ) &、新しいデタッチされた(読み取り:親シェルは子を待機しません)プロセスを作成します。

その後、アーカイブの抽出を最適化する必要があります。OSはすでにファイルアクセスをキャッシュしているはずなので、読み取りは問題ありません。ただし、tarはループが実行されるたびにアーカイブを解凍する必要があり、これは遅くなる可能性があります。アーカイブを一度解凍して結果を繰り返すと、次の場合に役立ちます。

local tempPath=`tempfile`
mkdir $tempPath && tar -zxf file.tar.gz -C $tempPath &&
find $tempPath -type f | while read FILENAME
do
        (if grep -l "string" "$FILENAME"
        then
                echo "$FILENAME contains string"
        fi) &
done && rm -r $tempPath

findここではtar、文字列を検索するファイルごとに、のターゲットディレクトリにあるファイルのリストを取得するために使用されます。

編集:grep -lジムが指摘したように、物事をスピードアップするために使用します。差出人man grep

   -l, --files-with-matches
          Suppress normal output; instead print the name of each input file from which output would
          normally have been printed.  The scanning will stop on the first match.  (-l is specified
          by POSIX.)
于 2012-12-21T02:20:05.067 に答える