我有数百个 zip 文件,想在其中找到特定文件。使用 grep 搜索文件名相当容易:
find . -name "*.zip" -exec unzip -Z -1 {} \; | grep png
这将给出所有文件名里面zip 文件。例如
icons/full/obj16/folder.png
icons/full/obj16/folderType_filter.png
icons/full/wizban/newfolder_wiz.png
但是我怎样才能在每行前面加上 zip 文件的名称,以便能够真正找到它呢?像这样:
dir1/a.zip:icons/full/obj16/folder.png
dir2/icons.zip:icons/full/obj16/folderType_filter.png
myicons.zip:icons/full/wizban/newfolder_wiz.png
答案1
运行这个:
gexp='\.png$' aexp='{print f":"$0}' find . -type f -name "*.zip" -exec sh -c '
for f do
unzip -Z -1 "$f" | grep -i "$gexp" | awk -F "" -v "f=$f" "$aexp"
done
' find-sh {} +
解释:
- 我使用
-type f
以防某些目录(或其他非常规文件)意外匹配-name "*.zip"
。我不想尝试unzip
目录。 find -exec
我使用从调用的shell为每个文件运行自定义管道由 预选find
。- 我过去
-exec … {} +
为每个文件生成远少于一个的 shell。现在,单个 shell 可以将多个路径作为命令行参数,我使用 循环遍历它们for
。 - 我传递了我想在环境中使用的静态表达式
grep
。awk
如果我将它们嵌入到 shell 代码中,那么我需要使用额外的转义和/或引号来混淆命令。单独传递表达式要干净得多。我可以将它们作为命令行参数传递给sh
,但随后我需要将它们保存在内壳的变量中,shift
然后才能循环实际路径(在我看来,这仍然比引用狂热要好)。 find-sh
解释如下:中的第二个 sh 是什么sh -c 'some shell code' sh
?- 我使用不区分大小写
grep -i
。 - 您的模式
grep
只是png
,它可以匹配例如stopngo
。我将其固定在行尾并添加了前导点。该点需要转义,因为未转义.
匹配正则表达式中的任何字符。 awk
将当前处理的文件(和)的路径添加:
到从 管道传输的每一行的开头grep
。有人可能会认为shellsed "s|^|$f:|"
扩展$f
的 会起作用;但是 的扩展$f
可能会破坏表达式(假设它包含|
,则代码注入是可能的)。如果我让 shell$f
在awk
代码中扩展,它也会同样存在缺陷。awk -v "f=$f"
我将路径作为f
变量存储在 中awk
(注意awk
变量和 shell 变量是独立的概念)。现在f
中awk
不能破坏代码,因为awk
知道它不是代码。此外,为 设计的整个表达式awk
是静态的,所以我可以首先将它传递到环境中。