递归查找所有存档格式的所有存档文件,并搜索它们的文件名模式


11

充其量我想打这样的电话:

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

...这样这个工具

  • 对给定路径进行递归扫描
  • 接受所有具有受支持的存档格式的文件,这些格式至少应是“最常见”的格式,例如zip,rar,7z,tar.bz,tar.gz ...
  • 并扫描档案文件列表中的相关名称模式(此处为*vacation*jpg

我知道如何使用查找工具tar,解压缩等。我可以将它们与Shell脚本结合使用,但是我正在寻找一个简单的解决方案,该解决方案可能是Shell一线式或专用工具(欢迎使用GUI工具提示,但我的解决方案必须基于命令行)。

Answers:


9

(改编自我如何通过压缩档案递归grep?

安装AVFS,该文件系统可提供对归档文件的透明访问。首先运行此命令一次,以设置计算机文件系统的视图,您可以在其中访问归档文件,就好像它们是目录一样:

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视图。
  • 对于每个档案,执行指定的shell代码段(使用$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的每个匹配项。匹配文件的名称在中$REPLY。设置reply数组会将匹配项转换为名称列表。
  • $REPLY\# 是档案的目录视图。
  • $REPLY\#/**/*vacation*.jpg匹配*vacation*.jpg存档中的文件。
  • N预选赛中,使图案水珠扩大到一个空列表,如果没有匹配。

9

如果您想要比AVFS解决方案更简单的方法,我编写了一个Python脚本来称为arkfind。你实际上可以做

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

它将以递归方式进行操作,因此您可以任意深度查看存档内的存档。


谢谢,贡献很大!特别是在没有AVFS的情况下。
mdo

如果它支持jar文件,那就太好了。
Chemik

@Chemik- 注意!这个周末我将做更多的工作:) JAR不应太难,我相信它实际上只是一个到外界的压缩文件。
2013年

@Chemik-我刚刚尝试过,无论如何它应该支持当前形式的JAR文件。您可以对其进行测试,如果它无法按预期工作,请在Github页面上提交错误?(我只是修复了一个错误,因此请务必更新您的副本。)
敬请原谅

1
是的,我现在看到了,它有效。您可以将“ JAR文件”添加到自述文件中:)
Chemik 2013年

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'

结果如:

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被使用了两次,因此您可以使用一个变量。

使用find可以使用PATH / TO / SEARCH


2

另一个可行的解决方案是 zgrep

zgrep -r filename *.zip

1
那是什么实现zgrep?不工作与一个附带GNU gzip/bin/zgrep: -r: option not supportedzgrep (gzip) 1.6
斯特凡Chazelas

2

恕我直言,用户友好性也应该受到重视:

 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

和焦油(这是未经测试的...)

 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

什么unzip实现可以处理7z或tar.gz文件?
斯特凡Chazelas

是的,这是一个错误。已纠正。对于正确的文件类型,绝对应该使用正确的二进制文件。作为操作方法收据...
Yordan Georgiev

0

libarchivebsdtar可以处理大多数的这些文件格式,所以你可以这样做:

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

您可以find通过以下方式使用GNU简化(并提高以区分大小写的方式匹配):

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标志的regexps 打印匹配文件的名称,然后确保未提取文件,例如:

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

请注意,它将在stderr上输出列表并追加>>到每一行。无论如何,bsdtar像大多数tar实现一样,如果它们包含换行符或反斜杠(呈现为\n\\)之类的字符,则它们可能会破坏显示的文件名。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.