我有一堆 tar.gz 文件,我想对它们执行“grep something * -Rin”,就像对它们执行非 tar.gzed 操作一样。我想保留它们的 tar.gzed 原样,但动态地对它们执行 grep,并查找带有前缀文件和行号的 grep 出现的情况。
就像是:
grep mytoken1 *.tar.gz -Rin
并得到如下结果:
my1.tar.gz,dir1/file2:123:mytoken1 在这一行 my2.tar.gz,dir2/file3:233:mytoken1 也在另一行中 [...]
有办法吗?
答案1
zgrep(或者,我们认为带有 -Z 标志的 grep)将允许您 grep 压缩文件,我认为它将告诉您很多您想要的信息,但是,如果您不花更多功夫查看标题,这不会给您文件名 :(
答案2
在发现在 .tar 或 .gz 文件中搜索的 Unix 脚本:
剧本 :
for file in $(tar -tzf file.tar.gz | grep '\.txt'); do
tar -Oxzf file.tar.gz "$file" | grep -B 3 --label="$file" -H "string-or-regex"
done
将尊重文件边界并报告文件名。该| grep '\.txt
部分可以根据您的需要进行调整或删除。
(-z
表示tar
它已被gzip
压缩。-t
列出内容。 -x
提取。 -O
重定向到标准输出而不是文件系统。较旧的tar
s 可能没有-O
或-z
标志,并且需要没有-
: 的标志,例如tar tz file.tar.gz
)
如果您的 grep 不支持这些标志,那么可以使用 awk :
#!/usr/bin/awk -f
BEGIN { context=3; }
{ add_buffer($0) }
/pattern/ { print_buffer() }
function add_buffer(line)
{
buffer[NR % context]=line
}
function print_buffer()
{
for(i = max(1, NR-context+1); i <= NR; i++) {
print buffer[i % context]
}
}
function max(a,b)
{
if (a > b) { return a } else { return b }
}
与 grep -B 不同,这不会合并相邻的匹配,因此可以重复两个不同匹配的 3 行内的行。
答案3
一种方法是使用这个快速技巧:
#!/usr/bin/ruby
=begin
Quick-and-dirty way to grep in *.tar.gz archives
Assumption:
each and every file read from any of the supplied tar archives
will fit into memory. If not, the data reading has to be rewritten
(a proxy that reads line-by-line would have to be inserted)
=end
require 'rubygems'
gem 'minitar'
require 'zlib'
require 'archive/tar/minitar'
if ARGV.size < 2
STDERR.puts "#{File.basename($0)} <regexp> <file>+"
exit 1
end
regexp = Regexp.new(ARGV.shift, Regexp::IGNORECASE)
for file in ARGV
zr = Zlib::GzipReader.new(File.open(file, 'rb'))
Archive::Tar::Minitar::Reader.new(zr).each do |e|
next unless e.file?
data = e.read
if regexp =~ data
data.split(/\n/).each_with_index do |l, i|
puts "#{file},#{e.full_name}:#{i+1}:#{l}" if regexp =~ l
end
end
end
end
这并不是说我会推荐它用于更大的档案,因为档案中的每个文件都会被读入内存(实际上是两次)。
如果您想要一个内存效率更高的版本,那么您要么采用不同的循环实现e.read
……或者,也许,采用完全不同的语言。;)
如果您真的感兴趣,我可以让它变得更高效一些......但就原始速度而言,它绝对无法与 C 或其他编译语言相比。
答案4
*nix 工具的模块化方法意味着没有简单的方法可以用 grep / tar / zcat 高效地完成此操作。理想情况下,你只需要解压文件一次,然后一次处理每个 tar 文件。这是我的尝试tgz-grep:
#!/usr/bin/python
import re,sys,tarfile
exp=re.compile(sys.argv[1])
tarfiles=sys.argv[2:]
for tfile in tarfiles:
tar=tarfile.open(tfile, mode='r|gz')
for file in tar:
name=file.name
count=0
for line in tar.extractfile(file):
count += 1
if exp.search(line):
print "%s,%s:%d:%s" % (tfile, name, count, line),
注意:这不执行目录递归(-R)或不区分大小写(-i),或 GNU grep 支持的其他选项,但添加它们并不困难。