Pergunta

Estou processando um arquivo enorme com (GNU) awk, (outras ferramentas disponíveis são: ferramentas Linux shell, alguns versão antiga (> 5,0) de Perl, mas não pode instalar módulos)

.

Meu problema: se algum campo1, campo2, field3 contêm X, Y, ZI deve procurar um arquivo em outro diretório que contém field4 e Field5 em uma linha, e inserir alguns dados do arquivo encontrado para a saída de corrente.

por exemplo:.

linha do arquivo real:

f1 f2 f3 f4 f5
X  Y  Z  A  B

Agora eu preciso procurar outro arquivo (em outro diretório), que contém por exemplo.

f1 f2 f3 f4
A  U  B  W

e escrever para STDOUT $0 do arquivo original, e f2 e f3 do arquivo encontrado, em seguida, processar a próxima linha do arquivo original.

É possível fazê-lo com awk?

Foi útil?

Solução

Deixe-me começar por dizer que a sua descrição do problema não é realmente útil. Da próxima vez, por favor, ser mais específico:. Você pode estar perdendo muito melhores soluções

Assim, a partir de sua descrição, eu entendo que você tem dois arquivos que contêm dados separados por espaços em branco. No primeiro arquivo, você quer combinar as três primeiras colunas contra alguns padrão de pesquisa. Se for encontrado, você quer encontrar todas as linhas em outro arquivo que contém a quarta e quinta e coluna da linha correspondente no primeiro arquivo. A partir dessas linhas, você precisa extrair a segunda e terceira coluna e, em seguida, imprimir a primeira coluna da primeira arquivo e o segundo eo terceiro a partir do segundo arquivo. Ok, aqui vai:

#!/usr/bin/env perl -nwa
use strict;
use File::Find 'find';
my @search = qw(X Y Z);

# if you know in advance that the otherfile isn't
# huge, you can cache it in memory as an optimization.

# with any more columns, you want a loop here:
if ($F[0] eq $search[0]
    and $F[1] eq $search[1]
    and $F[2] eq $search[2])
{
  my @files;
  find(sub {
      return if not -f $_;
      # verbatim search for the columns in the file name.
      # I'm still not sure what your file-search criteria are, though.
      push @files, $File::Find::name if /\Q$F[3]\E/ and /\Q$F[4]\E/;
      # alternatively search for the combination:
      #push @files, $File::Find::name if /\Q$F[3]\E.*\Q$F[4]\E/;
      # or search *all* files in the search path?
      #push @files, $File::Find::name;
    }, '/search/path'
  )
  foreach my $file (@files) {
    open my $fh, '<', $file or die "Can't open file '$file': $!";
    while (defined($_ = <$fh>)) {
      chomp;
      # order of fields doesn't matter per your requirement.
      my @cols = split ' ', $_;
      my %seen = map {($_=>1)} @cols;
      if ($seen{$F[3]} and $seen{$F[4]}) {
        print join(' ', $F[0], @cols[1,2]), "\n";
      }
    }
    close $fh;
  }
} # end if matching line

Ao contrário de solução de um outro cartaz que contém grande quantidade de chamadas de sistema, isto não cair de volta para o shell em tudo e, portanto, deve ser muito rápido.

Outras dicas

Este é o tipo de trabalho que me levou a passar de awk para perl em primeiro lugar. Se você estiver indo para fazer isso, você pode realmente encontrá-lo mais fácil para criar um shell script que cria script awk (s) a consulta e, em seguida, atualizar em etapas separadas.

(Eu escrevi tal uma besta para leitura / atualização do Windows-estilo ini arquivos -.. Que é feio Eu gostaria de poder ter perl usado)

Muitas vezes vejo a restrição "Eu não pode usar quaisquer módulos Perl", e quando isso não é uma pergunta lição de casa, muitas vezes é apenas devido a uma falta de informação. Sim, mesmo você pode usar CPAN contém as instruções sobre como instalar módulos do CPAN localmente sem ter privilégios de root . Outra alternativa é apenas para pegar o código fonte de um módulo CPAN e colá-lo em seu programa.

Nada disso ajuda se existem outros, não declaradas, restrições, como a falta de espaço em disco que impedem a instalação de (muitos) arquivos adicionais.

Isso parece funcionar para alguns arquivos de teste I criadas combinando seus exemplos. Envolvendo perl desta maneira (interpôs com grep) é provavelmente vai prejudicar o desempenho bastante, embora ...

## perl code to do some dirty work

for my $line (`grep 'X Y Z' myhugefile`) {
    chomp $line;
    my ($a, $b, $c, $d, $e) = split(/ /,$line);
    my $cmd = 'grep -P "' . $d . ' .+? ' . $e .'" otherfile';
    for my $from_otherfile (`$cmd`) {
        chomp $from_otherfile;
        my ($oa, $ob, $oc, $od) = split(/ /,$from_otherfile);
        print "$a $ob $oc\n";
    }
}

EDIT:. A solução de Uso tsee (acima), é muito mais bem-pensamento-out

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top