zgrep (или, как мы полагаем, grep с флагом -Z) позволит вам создавать сжатые файлы grep, и я думаю, что многое скажет вам о том, что вы хотите, но это не даст вам имя файла, если немного больше не смотреть на заголовок :(
Как сделать эквивалент «grep что-то * -Rin» в списке файлов tar.gz?
У меня есть куча файлов 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 ответов на вопрос
- Популярные
- Новые
- С комментариями
- Активные
Найден в скрипте 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
перенаправляет на стандартный вывод, а не на файловую систему. У более старых 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 строк двух разных совпадений.
Одним из способов было бы использовать этот быстрый взлом:
#!/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 или другими скомпилированными языками с точки зрения сырой скорости.
Я думаю, что это будет очень сложно.
На самом деле tar представляет собой объединение всех включаемых файлов с добавлением заголовков. Таким образом, в основном grep-in-tar
можно написать функцию, которая справится с этим и предоставит информацию о файле и номере строки (базовый grep с чтением заголовка и вычитанием номера строки). Я не слышал о такой программе.
Проблема с gzip. Это формат сжатия, поэтому вам нужно распаковать его, если вы хотите получить доступ к содержимому.
gunzip -c files.tgz | grep-in-tar
был бы способ сделать то, что вы хотите. На данный момент вы можете попробовать, gunzip -c files.tgz | grep -Rin
но он просто скажет, что двоичный файл совпадает.
Модульный подход к * 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, но добавить их будет непросто.
Похожие вопросы
-
9
grep все файлы .java в каталоге для конкретной строки
-
3
Может ли GNU Grep выводить выбранную группу?
-
5
Grep инструмент для XML
-
-
4
Как я могу рекурсивно grep определенных файлов в каталоге?
-
8
Linux grep или найти использование
-
4
Какая польза от? в команде grep .. и практическое использование
-
3
программно распаковать tar.gz за один шаг (на windows с 7zip)
-
5
Получение цветных результатов при использовании трубы от grep до менее
-
6
grep для Vista 64?
-
6
Linux: перечислить содержимое подкаталогов с указанным именем?