File 1:
Connect|20130320000023|UTC|PPP|[email protected]|[email protected]|0BCBE578|
File 2:
Connect|20130320000023|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Preciso encontrar registros correspondentes no Arquivo 1 e no Arquivo 2 na coluna 5. Portanto, do exposto acima, preciso retornar na saída:
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Muito obrigado,
Responder1
Método nº 1: grep e awk
Você pode usar este trecho para fazer isso:
$ grep -f <(awk -F '|' '{print $5}' file1) file2
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Detalhes
O bit que usa awk
analisa o primeiro arquivo, file1
retirando todas as quintas colunas. Esses valores são então usados como uma lista para grep
, que imprimirá quaisquer linhas no segundo arquivo que contenham uma correspondência.
Advertências com este método
Este método corresponderá a qualquer ocorrência da 5ª coluna de file1
in file2
.
Método nº 2: simplesmente estranho
Outra abordagem que foi usada no site no passado é usar o awk
recurso FNR da. É aqui que awk
irá iterar em 2 arquivos, passando pelo segundo arquivo linha por linha, para cada linha do primeiro.
Uma abordagem como essa resolveria isso. Coloque o seguinte em um arquivo cmds.awk
:
FNR == NR {
f1[$5] = $5
next
}
{ if ($5 == f1[$5]) print $0; }
Você pode então executar isso da seguinte maneira:
$ awk -F '|' -f cmds.awk file1 file2
OBSERVAÇÃO:Você poderia ter usado este awk
padrão:
FNR == NR {
f1[$5] = $5
next
}
{ if ($5 in f1) print $0; }
Exemplo
$ awk -F '|' -f s.awk file1 file2
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Advertências com este método
Essa abordagem só pode lidar com uma única instância de cada endereço de e-mail do file1
. Portanto, se houver 2 linhas com o mesmo valor para a 5ª coluna, não será possível distingui-las. Isso parece aceitável, dados os seus requisitos no OP.
Junte-se e classifique
Você também pode fazer isso usando join
e sort
.
$ join -t '|' -j 5 <(sort -k5,5 file2) <(sort -k5,5 file1) | sed 's/||.*//'
Isso usará o separador |
e juntará os arquivos classificados na 5ª coluna. Essa abordagem imprime as correspondências de file1
e file2
, então usamos sed
para cortar a segunda correspondência do final.
Exemplo
$ join -t '|' -j 5 <(sort -k5,5 file2) <(sort -k5,5 file1) | sed 's/||.*//'
[email protected]|Connect|20130320000025|UTC|PPP|[email protected]|0BCBE578
Responder2
Eu faria tudo em perl:
$ perl -F'\|' -ane '$k{$F[4]}++; print if $k{$F[4]}>1' file1 file2
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
-a
ativa a divisão automática de campos no array@F
.-F'\|'
define o delimitador de campo-a
para|
.- Para cada linha processada, salve o 5º campo (os índices do array começam em
0
perl) como uma chave hash ($k{$F[4]}++
e aumente seu valor em um. Na segunda vez que um campo for visto, esse valor será 2. - O script irá processar cada linha de ambos os arquivos (
file1
antesfile2
) e imprimir a linha se o 5º campo já tiver sido visto antes, ou seja, se$k{$F[4]}
for maior que um.
Isso pressupõe que nenhuma quinta coluna seja repetida dentro domesmoarquivo. Se este não for o caso e algumas colunas puderem estar duplicadas no mesmo arquivo, use isto:
perl -e 'open(A,"$ARGV[0]"); while(<A>){@F=split(/\|/);$k{$F[4]}++;}
open(B,"$ARGV[1]"); while(<B>){@F=split(/\|/); print if $k{$F[4]}
}' file1 file2
Responder3
Se os tamanhos dos arquivos forem comparáveis, a solução ideal ésort
ambos os arquivos pela coluna que você está interessado e entãojoin
-los por essa coluna. Se os tamanhos dos arquivos forem N
e M
o tempo de execução assintótico for O(N*log(N)+M*log(M))
.
Se um dos arquivos for muito menor que o outro, a O(N*M)
solução nas outras respostas será melhor.