Como fazer o equivalente a “grep something * -Rin” na lista de arquivos tar.gz?

5

Eu tenho um monte de arquivos tar.gz e eu quero fazer um "grep something * -Rin" como eu faria com eles se eles não fossem tar.gzed. Eu quero mantê-los tar.gzed como estão, mas grep on-the-fly e encontrar as ocorrências do meu grep com o arquivo de prefixo e número de linha.

Algo como:

grep mytoken1 *.tar.gz -Rin

e obtenha algo como:

my1.tar.gz,dir1/file2:123:mytoken1 is in this line  
my2.tar.gz,dir2/file3:233:mytoken1 is also in this other line  
[...]  

Existe uma maneira de fazer isso?

    
por 719016 08.06.2011 / 11:20

5 respostas

5

zgrep (ou, acreditamos, grep com o sinalizador -Z) permitirá que você faça um grep nos arquivos compactados e eu acho que vai te dizer muito do que você quer, mas isso não dá a você o nome do arquivo sem um pouco mais de trabalho olhando para o cabeçalho :(

    
por 31.01.2012 / 07:50
4

Encontrado em script Unix para pesquisar em um arquivo. arquivo tar ou .gz :

O 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

respeitará os limites dos arquivos e reportará os nomes dos arquivos. A parte | grep '\.txt pode ser adaptada às suas necessidades ou descartada.

( -z informa tar é gzip compactado. -t lista o conteúdo. -x extractos. -O redireciona para saída padrão em vez do sistema de arquivos.% mais antigostar s podem não tem o sinal -O ou -z e desejará os sinalizadores sem - : por exemplo, tar tz file.tar.gz )

Se o seu grep não suporta estes flags, então pode-se usar o 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 }
}

Isso não aglutinará correspondências adjacentes, ao contrário de grep -B, e pode, portanto, repetir linhas que estão dentro de 3 linhas de dois jogos diferentes.

    
por 31.01.2012 / 09:50
2

Uma maneira seria usar esse hack rápido:

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

o que não quer dizer que eu recomendaria para arquivos maiores, já que cada arquivo do arquivo é lido na memória (duas vezes, na verdade).

Se você quiser uma versão um pouco mais eficiente de memória, terá que executar uma implementação diferente do e.read loop ... ou, talvez, com uma linguagem diferente. ;)

Eu poderia torná-lo um pouco mais eficiente se você estiver realmente interessado ... mas definitivamente não se compara com C ou outras linguagens compiladas, em termos de velocidade bruta.

    
por 06.02.2012 / 02:28
0

Acho que isso será muito complicado.

Na verdade, o tar é basicamente uma concatenação de todos os seus arquivos de inclusão, com adição de cabeçalhos. Então, basicamente, uma função grep-in-tar poderia ser escrita para lidar com isso e fornecer informações sobre o arquivo e o número da linha (grep básico com leitura do cabeçalho e subtração do número da linha). Eu não ouvi falar de tal programa.

O problema é com o gzip. Este é um formato de compactação, então você precisa descompactá-lo se quiser acessar o conteúdo.

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

seria uma maneira de fazer o que você quer. No momento, você pode tentar gunzip -c files.tgz | grep -Rin , mas ele diz apenas que o arquivo binário é compatível.

    
por 08.06.2011 / 11:40
0

A abordagem modular para ferramentas * nix significa que não há uma maneira simples de fazer isso eficientemente com grep / tar / zcat. Idealmente, você deseja descompactar os arquivos apenas uma vez e processar cada arquivo tar em uma única passagem. Aqui está minha tentativa em 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),

Nota: isto não faz recursão de diretório (-R) ou insensibilidade de caso (-i), ou outras opções suportadas pelo GNU grep, mas elas não seriam complicadas de se adicionar.

    
por 07.02.2012 / 00:45

Tags