我正在尝试找出哪些模块use Test::Version
在cpan中。所以我用过minicpan
来镜像它。我的问题是我需要遍历下载的档案,并 grep 档案中的文件。谁能告诉我我该怎么做?最好以某种方式告诉我存档中的哪个文件以及它位于哪一行。
(注意:它们并不都是 tarball,有些是 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 视图。 - 对于每个存档,执行指定的 shell 片段(使用
$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'\')
将 CODE 应用于 PATTERN 的每个匹配项。匹配文件的名称位于$REPLY
.设置reply
数组会将匹配项转换为名称列表。$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
这对于 tarball 中的位置并不是很具体。希望有人能给出更好的答案。
答案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