Wie mache ich das Äquivalent von "grep etwas * -Rin" auf der Liste der tar.gz-Dateien?

2991
719016

Ich habe eine Reihe von tar.gz-Dateien und möchte einen "grep etwas * -Rin" machen, so wie ich es für sie tun würde, wenn sie nicht tar.gzed wären. Ich möchte, dass sie tar.gzed bleiben, wie sie sind, aber grep sie schnell und finde die Vorkommen meines grep mit dem vorangestellten Dateinamen und der Zeilennummer.

So etwas wie:

grep mytoken1 * .tar.gz -Rin 

und etwas bekommen wie:

my1.tar.gz, dir1 / file2: 123: mytoken1 steht in dieser Zeile  my2.tar.gz, dir2 / file3: 233: mytoken1 ist auch in dieser anderen Zeile  [...]  

Gibt es eine Möglichkeit, dies zu tun?

5

5 Antworten auf die Frage

5
Joe

zgrep (oder, glaube wir, grep mit dem Flag -Z) lässt Sie die komprimierten Dateien grep und ich denke, Sie werden viel darüber sagen, was Sie wollen, aber dies gibt Ihnen nicht den Dateinamen, ohne dass Sie etwas mehr mit der Header :(

http://www.nsc.ru/cgi-bin/www/unix_help/unix-man?zgrep+1 Demnach ist zgrep dasselbe wie grep mit der -Z-Flag (muss zlib kompiliert werden, tho), ich gebe ' Ich habe ein Terminal vor mir, aber ich würde meinen, das würde funktionieren. SW. vor 12 Jahren 0
* erröten * es ist wie wenn ich ls und l herausfand. Ich fühle mich erwachsen ... Joe vor 12 Jahren 1
+1 zgrep sollte funktionieren, da das `tar'-Format ** wortwörtlich ** Kopien des Dateiinhalts sowie einige Header-Informationen und Füllbytes enthält. Mr Shunz vor 12 Jahren 0
Dies zeigt nicht an, in welcher Datei im Archiv sich das Muster befand. harrymc vor 12 Jahren 0
Haben mit Informationen aus Kommentaren bearbeitet. Joe vor 12 Jahren 0
@Joe Alles Gute d00d, es gibt eine ganze Familie von 'z'-Befehlen. Z sind die einzigen, die mir im Moment in den Sinn kommen, aber Google wird Ihnen da draußen helfen. :) SW. vor 12 Jahren 0
4
harrymc

Found in Unix script to search within a .tar or .gz file :

The script :

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 

will respect file boundaries and report the file names. The | grep '\.txt part can be adapted to your needs or dropped.

(-z tells tar it is gzip compressed. -t lists the contents. -x extracts. -O redirects to standard output rather than the file system. Older tars may not have the -O or -z flag, and will want the flags without -: e.g. tar tz file.tar.gz)

If your grep does not support these flags, then one can use 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 } } 

This will not coalesce adjacent matches, unlike grep -B, and can thus repeat lines that are within 3 lines of two different matches.

2
Wejn

Eine Möglichkeit wäre, diesen schnellen Hack zu verwenden:

#!/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 "# <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 "#,#:#:#" if regexp =~ l end end end end 

Das heißt nicht, dass ich es für größere Archive empfehlen würde, da jede Datei aus dem Archiv in den Speicher gelesen wird (tatsächlich zweimal).

Wenn Sie eine etwas speichereffizientere Version wünschen, müssen Sie entweder eine andere Implementierung der e.readSchleife vornehmen ... oder vielleicht eine andere Sprache insgesamt. ;)

Ich könnte es ein bisschen effizienter machen, wenn Sie wirklich interessiert sind ... aber es wird definitiv nicht mit C oder anderen kompilierten Sprachen verglichen, was die Rohgeschwindigkeit angeht.

Welche Version von Ruby soll ich verwenden? $ ruby ​​./tar_search.rb DSM 1.tar.gz 2.tar.gz /usr/lib/ruby/1.9.1/rubygems.rb:762:in `report_activate_error ': RubyGem minitar konnte nicht gefunden werden (> = 0) (Gem :: LoadError) von /usr/lib/ruby/1.9.1/rubygems.rb:219:in `enable 'von /usr/lib/ruby/1.9.1/rubygems.rb:1065:in` gem' von ./tar_search.rb:13:in `
'
719016 vor 12 Jahren 0
Ich habe am 1.8.7 entwickelt. Das Hauptproblem ist jedoch das Fehlen des Edelsteins "Minitar". Korrigieren Sie das von Shell: `gem install minitar`; dann sollte es klappen. Auch Ruby 1.9.1 funktioniert einwandfrei (nach der Installation des Edelsteins). Wejn vor 12 Jahren 0
0
M'vy

Ich denke, das wird sehr knifflig.

Tatsächlich ist tar im Grunde eine Verkettung aller Include-Dateien mit Kopfzeilen. Im Grunde könnte eine grep-in-tarFunktion geschrieben werden, die sich damit befasst und Informationen über die Datei- und Zeilennummer bereitstellt (einfaches grep mit Header-Lesen und Zeilennummer-Subtraktion). Ich habe von einem solchen Programm nichts gehört.

Das Problem ist mit GZIP. Dies ist ein Komprimierungsformat, das Sie dekomprimieren müssen, wenn Sie auf den Inhalt zugreifen möchten.

gunzip -c files.tgz | grep-in-tar 

wäre eine Möglichkeit, das zu tun, was Sie wollen. Im Moment können Sie es versuchen, gunzip -c files.tgz | grep -Rinaber es wird nur gesagt, dass die Binärdatei übereinstimmt.

0
Phil

The modular approach to *nix tools means that there's no simple way to do this efficiently with grep / tar / zcat. Ideally you want to decompress the files only once, and process each tar file in a single pass. Here's my attempt at 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), 

Note: this doesn't do directory recursion (-R) or case-insensitvity (-i), or other options supported by GNU grep, but they wouldn't be tricky to add.