Как сделать эквивалент «grep что-то * -Rin» в списке файлов tar.gz?

2909
719016

У меня есть куча файлов tar.gz, и я хочу сделать «grep что-то * -Rin», как если бы они не были tar.gzed. Я хочу, чтобы они сохранялись в неизменном виде, но сгораю на них на лету и нахожу вхождения моего grep с префиксным файлом и номером строки.

Что-то вроде:

grep mytoken1 * .tar.gz -Rin 

и получить что-то вроде:

my1.tar.gz, dir1 / file2: 123: mytoken1 находится в этой строке  my2.tar.gz, dir2 / file3: 233: mytoken1 также находится в этой другой строке  [...]  

Есть ли способ сделать это?

5

5 ответов на вопрос

5
Joe

zgrep (или, как мы полагаем, grep с флагом -Z) позволит вам создавать сжатые файлы grep, и я думаю, что многое скажет вам о том, что вы хотите, но это не даст вам имя файла, если немного больше не смотреть на заголовок :(

http://www.nsc.ru/cgi-bin/www/unix_help/unix-man?zgrep+1 В соответствии с этим zgrep аналогично grep с флагом -Z (нужно скомпилировать zlib, хотя), я не Передо мной нет терминала, но я думаю, это сработает. SW. 12 лет назад 0
* краснеет * это как когда я узнал про ls и l. Я чувствую себя взрослым ... Joe 12 лет назад 1
+1 zgrep должен работать, так как формат `tar` содержит ** дословно ** копии содержимого файла, плюс некоторую информацию заголовка и байты заполнения. Mr Shunz 12 лет назад 0
Это не показывает, в каком файле архива был найден шаблон. harrymc 12 лет назад 0
Отредактировал с информацией из комментариев. Joe 12 лет назад 0
@Joe Всем хорошего d00d, есть целое семейство команд 'z', на данный момент на ум приходят z , но Google поможет вам в этом. :) SW. 12 лет назад 0
4
harrymc

Найден в скрипте Unix для поиска в файле .tar или .gz :

Сценарий :

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перенаправляет на стандартный вывод, а не на файловую систему. У более старых tars может не быть флага -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 строк двух разных совпадений.

2
Wejn

Одним из способов было бы использовать этот быстрый взлом:

#!/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 

Нельзя сказать, что я бы порекомендовал его для больших архивов, так как каждый файл из архива читается в память (фактически, дважды).

Если вам нужна более эффективная для памяти версия, вам придется либо использовать другую реализацию e.readцикла ... или, возможно, вообще другой язык. ;)

Я мог бы сделать его немного более эффективным, если вы действительно заинтересованы ... но он определенно не сравнится с C или другими скомпилированными языками с точки зрения сырой скорости.

Какую версию ruby ​​мне следует использовать? $ 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 (> = 0) (Gem :: LoadError) из /usr/lib/ruby/1.9.1/rubygems.rb:219:in `активировать 'из /usr/lib/ruby/1.9.1/rubygems.rb:1065:in` gem' от ./tar_search.rb:13:in `
'
719016 12 лет назад 0
Я разработал на 1.8.7. Тем не менее, основной проблемой является отсутствие драгоценного камня `minitar`. Исправьте это из оболочки: `gem install minitar`; тогда это должно работать. Также Ruby 1.9.1 работает нормально (после установки гема). Wejn 12 лет назад 0
0
M'vy

Я думаю, что это будет очень сложно.

На самом деле tar представляет собой объединение всех включаемых файлов с добавлением заголовков. Таким образом, в основном grep-in-tarможно написать функцию, которая справится с этим и предоставит информацию о файле и номере строки (базовый grep с чтением заголовка и вычитанием номера строки). Я не слышал о такой программе.

Проблема с gzip. Это формат сжатия, поэтому вам нужно распаковать его, если вы хотите получить доступ к содержимому.

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

был бы способ сделать то, что вы хотите. На данный момент вы можете попробовать, gunzip -c files.tgz | grep -Rinно он просто скажет, что двоичный файл совпадает.

0
Phil

Модульный подход к * nix tools означает, что не существует простого способа сделать это эффективно с помощью 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, но добавить их будет непросто.