如何通过.gz文件递归grep?


135

我正在使用脚本定期下载我的gmail邮件,该邮件将原始.eml压缩为.gz文件。该脚本每天创建一个文件夹,然后将每条消息压缩到其自己的文件中。

我想要一种在档案库中搜索“字符串”的方法。

仅Grep似乎无法做到这一点。我也尝试过SearchMonkey。


16
使用zgrepzgrep - search possibly compressed files for a regular expression
Arkadiusz Drabczyk 2015年

Answers:


141

如果要递归grep当前目录中的所有.eml.gz文件,则可以使用:

find . -name \*.eml.gz -print0 | xargs -0 zgrep "STRING"

您必须转义第一个,*以便外壳程序不解释它。-print0告诉find在找到的每个文件之后打印一个空字符;xargs -0从标准输入读取并在每个文件之后运行命令;zgrep的工作方式类似于grep,但先解压缩文件。


2
“ -print0”和“ -0”不是必需的。xargs默认使用'\ n'。
Jaime M.

1
如果路径中可能有空格字符,则必须使用它们。除了复杂之外,没有其他理由不使用它们。
Daniel Griscom 2015年

2
zgrep实际上似乎比grep在未压缩文件上运行快。一定是因为压缩文件可以从HD读取并且解压缩的速度比从HD读取未压缩的文件要快。
Geremia'8

@JaimeM。默认情况下xargs使用空格(空格)。当然,文件中几乎永远不会包含换行符,但是空格并不是闻所未闻的(即使大多数UNIXy类型都不喜欢它们)。就是说,您可以简化而不必更加担心空格:find . -name '*.eml.gz' -exec zgrep "STRING" {} +每次启动时都会得到许多相同的参数xargs-print0/ 的安全性-0,并且所有操作都不会产生额外的过程启动和管道操作,而且非常简洁。-exec+POSIX指定的,所以据我所知,它应该在大多数最近的类似UNIX的系统上。
ShadowRanger

@Jared是否有一种方法可以仅在知道文件模式的开头的情况下进行通配符搜索?例如,我有.gz文件,这些文件的末尾都有日期/时间戳。ABCLog04_18_18_2_21.gz 有没有一种方法可以递归查找以ABC *开头的文件。我尝试\*.eml.gz在上面的示例中替换为,ABCLog*并收到有关文件格式的错误。:find: paths must precede expression: ABCLog-2018-03-12-10-16-1.log.gz Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
DevelopingDeveloper

68

这里有很多混乱,因为不只是一个zgrep。我有我的系统上两个版本,zgrepgzipzgrepzutils。前者只是一个调用的包装器脚本gzip -cdfq。它不支持该-r, --recursive开关。1
后者是一个c++程序,它支持-r, --recursive选项。
运行zgrep --version | head -n 1将显示其中的哪一个(如果有)是默认值:

zgrep (gzip) 1.6

是包装脚本,

zgrep (zutils) 1.3

cpp可执行文件。
如果有后者,则可以运行:

zgrep 'pattern' -r --format=gz /path/to/dir

无论如何,如建议的那样,find+ zgrep可以在以下两个版本中同样有效zgrep

find /path/to/dir -name '*.gz' -exec zgrep -- 'pattern' {} +

如果zgrep系统中缺少此文件(极不可能),可以尝试:

find /path/to/dir -name '*.gz' -exec sh -c 'gzip -cd "$0" | grep -- "pattern"' {} \;

但有一个主要缺点:您将不知道匹配项在哪里,因为在匹配行之前没有文件名。


1:因为这有问题


1
如果zgrep无法使用zutils,则可以使用来在Ubuntu中安装它sudo apt-get install zutils
therealmarv

1
接续@therealmarv ...,然后Ubuntu将使用zutils zgrep代替gzip之一。然后-r起作用!
伊利亚·林恩

有没有办法打印与之匹配的文件的行号?
DogEatDog

@DogEatDog-与一样grep -nzgrep -n将打印行号。在手册中...
don_crissti

7

ag是的变体 grep,具有一些不错的额外功能。

  • 有-z选项用于压缩文件,
  • 具有许多ack功能。
  • 它很快

所以:

ag -r -z your-pattern-goes-here   folder

如果未安装,

apt-get install silversearcher-ag   (debian and friends)
yum install the_silver_searcher     (fedora)
brew install the_silver_searcher    (mac)

1
ag: truncated file: Success结果我得到了。我还应该添加其他标志吗?
2015年

4

单独进行递归很容易:

   -r, --recursive
          Read all files  under  each  directory,  recursively,  following
          symbolic  links  only  if they are on the command line.  This is
          equivalent to the -d recurse option.

   -R, --dereference-recursive
          Read all files under each directory,  recursively.   Follow  all
          symbolic links, unlike -r.

但是,对于压缩文件,您需要以下内容:

shopt globstar 
for file in /path/to/directory/**/*gz; do zcat ""$file" | grep pattern; done

path/to/directory 应该是包含每天子目录的父目录。


zgrep是明显的答案,但不幸的是,它不支持该-r标志。来自man zgrep

这些grep选项将导致zgrep终止,并显示错误代码:(-[d rR zZ] | --di * | --exc * | --inc * | --rec * | --nu *)。


3

如果您的系统具有zgrep,则只需

zgrep -irs your-pattern-goes-here the-folder-to-search-goes-here/

如果您的系统没有zgrep,则可以使用find命令对每个文件运行zcat和grep,如下所示:

find the-folder-to-search-goes-here/ -name '*.gz' \ -exec sh -c 'echo "Searching {}" ; zcat "{}" | grep your-pattern-goes-here ' \;


请原谅我这个问题……要搜索的文件有两层。〜/ gmvault-db / db / 2015-02包含每个存档月份的文件夹,然后在该文件夹下存储该月份的.gz文件。如果我要在整个树中搜索.mil,那是我会做的吗?找到〜/ gmvault-db / db / -name'* .gz'\ -exec sh -c'echo“正在搜索{}”;zcat“ {}” | grep .mil'\;
Kendor

1
很好--irs中的“ r”将导致zgrep递归搜索。默认情况下,find命令以递归方式操作,因此任何以.gz结尾的文件都将被zcat并传递到grep中。(并且{}将被扩展到将要搜索的文件的相对路径)。因此,当您受到打击时,它将由 Searching ~/gmvault-db/db/2015-02/03/whatever.gz
Nate)来自卡拉马祖2015年

这就是我得到的结果:查找:“路径必须在表达式之前:-exec”这是我使用的命令:查找〜/ gmvault-db / db / -name'* .gz'\ -exec sh -c'echo“ }“;zcat“ {}” | grep .mil'\;
肯多

去掉'* .gz'和-exec之间的反斜杠。
Nate来自卡拉马祖2015年

4
zgrep-r出于某种原因不会采取行动。在man zgrep(也请参阅我的答案)中提到。
terdon

0

xzgrep -l“字符串” ./*/*.eml.gz

xzgrep是zgrep实用程序的衍生版本(减去/ bin / xzgrep)

在手册页中:

xzgrep对可能未压缩或使用xz(1),lzma(1),gzip(1),bzip2(1)或lzop(1)压缩的文件调用grep(1)。指定的所有选项都直接传递到grep(1)。

-l打印匹配的文件名

-R递归将不起作用,因为脚本中明确禁止它,但是简单的shell遍历应该可以使我们到达

./*/*.eml.gz

从./today/sample.eml.gz的相对路径匹配,在该实例的所有实例上都比我们在外壳中的相对位置低一级,并且以“ .eml.gz”结尾

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.