多様なアーカイブ形式のすべてのアーカイブファイルを再帰的に検索し、ファイル名パターンを検索する


11

せいぜい私はこのような電話をしたいと思います:

$searchtool /path/to/search/ -contained-file-name "*vacation*jpg"

...このツールが

  • 指定されたパスを再帰的にスキャンします
  • サポートされているアーカイブ形式のすべてのファイルを取得します。zip、rar、7z、tar.bz、tar.gzなどの「最も一般的な」形式である必要があります...
  • アーカイブのファイルリストをスキャンして、問題の名前パターンを探します(ここ*vacation*jpg

検索ツール、tar、unzipなどの使用方法を知っています。これらをシェルスクリプトと組み合わせることができますが、シェルのワンライナーまたは専用ツールである可能性のあるシンプルなソリューションを探しています(GUIツールへのヒントは大歓迎ですが、私のソリューションはコマンドラインベースである必要があります)。

回答:


9

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

アーカイブ内の透過的なアクセスを提供するファイルシステムであるAVFSをインストールします。まず、このコマンドを1回実行して、マシンのファイルシステムのビューを設定します。このビューでは、アーカイブがディレクトリであるかのようにアクセスできます。

mountavfs

この後/path/to/archive.zip、が認識されたアーカイブである場合~/.avfs/path/to/archive.zip#、アーカイブのコンテンツを含むように見えるディレクトリです。

find ~/.avfs"$PWD" \( -name '*.7z' -o -name '*.zip' -o -name '*.tar.gz' -o -name '*.tgz' \) \
     -exec sh -c '
                  find "$0#" -name "*vacation*.jpg"
                 ' {} 'Test::Version' \;

説明:

  • AVFSファイルシステムをマウントします。
  • でアーカイブファイルを探します~/.avfs$PWD。これは、現在のディレクトリのAVFSビューです。
  • 各アーカイブについて、指定したシェルスニペットを実行します($0=アーカイブ名と$1=検索するパターンを使用)。
  • $0#は、アーカイブのディレクトリビューです$0
  • {\}{}外側が引数の内部でfind置換される場合に必要となるのではなく(そうすることもしないこともある)。{}-exec ;

またはzsh≥4.3の場合:

mountavfs
ls -l ~/.avfs$PWD/**/*.(7z|tgz|tar.gz|zip)(e\''
     reply=($REPLY\#/**/*vacation*.jpg(.N))
'\')

説明:

  • ~/.avfs$PWD/**/*.(7z|tgz|tar.gz|zip) 現在のディレクトリとそのサブディレクトリのAVFSビューのアーカイブに一致します。
  • PATTERN(e\''CODE'\')PATTERNの各一致にCODEを適用します。一致したファイルの名前はにあります$REPLYreply配列を設定すると、一致が名前のリストに変わります。
  • $REPLY\# アーカイブのディレクトリビューです。
  • $REPLY\#/**/*vacation*.jpg*vacation*.jpgアーカイブ内のファイルと一致します。
  • Nグロブ修飾子は一致しない場合、パターンは空のリストに展開されます。

9

AVFSソリューションよりも簡単なものが必要な場合は、それを実行するためのarkfindというPythonスクリプトを作成しました。あなたは実際に行うことができます

$ arkfind /path/to/search/ -g "*vacation*jpg"

これは再帰的に行われるため、アーカイブ内のアーカイブを任意の深さで見ることができます。


ありがとう、いい貢献を!特にAVFSがオプションでない場合。
mdo 2013

それがjarファイルをサポートしているならそれは素晴らしいでしょう。
Chemik 2013年

@Chemik- 注目!今週末はもう少し作業をします:) JARはそれほど難しくないはずです。外の世界への単なるzipファイルだと思います。
2013年

@Chemik-試したところ、とにかく現在の形式のJARファイルをサポートするはずです。テストしてみて、期待どおりに動作しない場合は、Githubページにバグを報告してください。(私はバグを修正しただけなので、必ずコピーを更新してください。)
2013年

1
はい、わかりました。うまくいきました。READMEに「JARファイル」を追加できます:)
Chemik

2

私の通常の解決策:

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|DESIRED_FILE_TO_SEARCH'

例:

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|characterize.txt'

Resulsは次のようなものです。

foozip1.zip:
foozip2.zip:
foozip3.zip:
    DESIRED_FILE_TO_SEARCH
foozip4.zip:
...

ヒットしたzipファイルのみが必要な場合:

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|FILENAME' | grep -B1 'FILENAME'

ここでのFILENAMEは2回使用されるため、変数を使用できます。

findを使用すると、PATH / TO / SEARCHを使用できます



2

私見の使いやすさも同様にbashのものでなければなりません:

 while read -r zip_file ; do echo "$zip_file" ; unzip -l "$zip_file" | \
 grep -i --color=always -R "$to_srch"; \
 done < <(find . \( -name '*.7z' -o -name '*.zip' \)) | \
 less -R

とtar(これはテストされていません...)

 while read -r tar_file ; do echo "$tar_file" ; tar -tf  "$tar_file" | \
 grep -i --color=always -R "$to_srch"; \
 done < <(find . \( -name '*.tar.gz' -o -name '*.tar' \)) | \
 less -R

unzip7zまたはtar.gzファイルを処理できる実装は何ですか?
ステファンChazelas

ええ、それはバグです...修正されました...正しいファイルタイプには必ず正しいバイナリを使用する必要があります...私は、ワンライナーをデモンストレーションすることを目的としただけです...これはほぼ準備完了の状態になるでしょう。ハウツーレシートとして...
ヨルダンゲオルギエフ

0

libarchiveさんはbsdtarあなたができるので、それらのファイルフォーマットのほとんどを処理することができます:

find . \( -name '*.zip' -o     \
          -name '*.tar' -o     \
          -name '*.tar.gz' -o  \
          -name '*.tar.bz2' -o \
          -name '*.tar.xz' -o  \
          -name '*.tgz' -o     \
          -name '*.tbz2' -o    \
          -name '*.7z' -o      \
          -name '*.iso' -o     \
          -name '*.cpio' -o    \
          -name '*.a' -o       \
          -name '*.ar' \)      \
       -type f                 \
       -exec bsdtar tf {} '*vacation*jpg' \; 2> /dev/null

あなたはGNU findで次のように単純化することができます(大文字と小文字を区別せずに一致するように改善することができます):

find . -regextype egrep \
       -iregex '.*\.(zip|7z|iso|cpio|ar?|tar(|\.[gx]z|\.bz2)|tgz|tbz2)' \
       -type f \
       -exec bsdtar tf {} '*vacation*jpg' \; 2> /dev/null

ただし、これらの*vacation*jpgファイルが見つかったアーカイブのパスは出力されません。その名前を印刷するには、最後の行を次のように置き換えます。

-exec sh -ac '
   for ARCHIVE do
     bsdtar tf "$ARCHIVE" "*vacation*jpg" |
       awk '\''{print ENVIRON["ARCHIVE"] ": " $0}'\''
   done' sh {} + 2> /dev/null

次のような出力が得られます。

./a.zip: foo/blah_vacation.jpg
./a.zip: bar/blih_vacation.jpg
./a.tar.gz: foo/blah_vacation.jpg
./a.tar.gz: bar/blih_vacation.jpg

またはzsh

setopt extendedglob # best in ~/.zshrc
for archive (**/*.(#i)(zip|7z|iso|cpio|a|ar|tar(|.gz|.xz|.bz2)|tgz|tbz2)(.ND)) {
  matches=("${(f@)$(bsdtar tf $archive '*vacation*jpg' 2> /dev/null)"})
  (($#matches)) && printf '%s\n' "$archive: "$^matches
}

ただある他のファイル形式の多数存在することに留意されたいziptgzのように変装したファイル.jarまたは.docxファイル。それらをfind/ zsh検索パターンに追加できbsdtar、拡張子は関係ありません(ファイルのタイプを判別するために拡張子に依存しません)。

ことを注意*vacation*.jpg上記の完全アーカイブメンバーのパスに一致しているだけでなく、ファイル名、それは上でマッチするようvacation.jpgにも上vacation/2014/file.jpg

ファイル名のみを照合するには、抽出モードを使用-sし、正規表現とpフラグを使用して一致するファイルの名前を出力する(置換)を使用し、次のようにファイルが抽出されないようにします。

bsdtar -'s|.*vacation[^/]*$||' -'s|.*||' -xf "$archive"

stderrにリストを出力し、>>すべての行に追加することに注意してください。いずれの場合も、bsdtarほとんどのtar実装と同様に、改行やバックスラッシュ(\nまたはとしてレンダリングされた\\)などの文字が含まれている場合、ファイル名が表示される場合があります。

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