Tenho certeza de que encontrei um comando unix que poderia imprimir as linhas comuns de dois ou mais arquivos. Alguém sabe o nome? Era muito mais simples que diff
.
unix
shell
command-line
muito php
fonte
fonte
comm
requer arquivos de entrada classificados. Se você quer apenas linha por linha comum, é ótimo. Mas se você quiser o que eu chamaria de "anti-diff",comm
não faz o trabalho.pr-123-xy-45
arquivo2ec11_orop_pr-123-xy-45.gz
. Eu preciso file3 contendoec11_orop_pr-123-xy-45.gz
Respostas:
O comando que você está procurando é
comm
. por exemplo:-Aqui:
-1 : suprime a coluna 1 (linhas exclusivas para 1.sorted.txt)
-2 : suprime a coluna 2 (linhas exclusivas para 2.sorted.txt)
fonte
grep
faz algumas coisas estranhas que você não pode esperar. Especificamente, tudo1.txt
será interpretado como uma expressão regular e não como uma sequência simples. Além disso, qualquer linha em branco1.txt
corresponderá a todas as linhas2.txt
. Entãogrep
, só funcionará em situações muito específicas. Você pelo menos gostaria de usarfgrep
(ougrep -f
), mas o problema da linha em branco provavelmente causará estragos nesse processo.grep -F -x -f file1 file2
comm
comando em 3 arquivos separados? A resposta era grande demais para caber confortavelmente aqui.Para aplicar facilmente o comando comm a arquivos não classificados , use a substituição de processo do Bash :
Portanto, os arquivos abc e def têm uma linha em comum, aquela com "132". Usando comm em arquivos não classificados:
A última linha não produziu saída, a linha comum não foi descoberta.
Agora use comm em arquivos classificados, classificando os arquivos com substituição de processo:
Agora temos a linha 132!
fonte
sort abc > abc.sorted
,sort dev > def.sorted
e depoiscomm -12 abc.sorted def.sorted
?Para complementar o one-liner Perl, aqui está o seu
awk
equivalente:Isso lerá todas as linhas da
file1
matrizarr[]
e, em seguida, verificará se cada linhafile2
já existe na matriz (ou sejafile1
). As linhas encontradas serão impressas na ordem em que aparecemfile2
. Observe que a comparaçãoin arr
usa a linha inteira defile2
como índice para a matriz, portanto, somente reportará correspondências exatas em linhas inteiras.fonte
perl
os, porque). Graças a um milhão, Sra.Talvez você queira dizer
comm
?O segredo para encontrar essas informações são as páginas de informações. Para programas GNU, eles são muito mais detalhados do que suas páginas de manual. Tente
info coreutils
e ele listará todos os pequenos utilitários úteis.fonte
Enquanto
fornece as diferenças de dois arquivos (o que está no 2.txt e não no 1.txt), você pode facilmente fazer um
coletar todas as linhas comuns, o que deve fornecer uma solução fácil para o seu problema. Se você classificou os arquivos, você deve fazer isso
comm
. Saudações!fonte
grep
faz algumas coisas estranhas que você não pode esperar. Especificamente, tudo1.txt
será interpretado como uma expressão regular e não como uma sequência simples. Além disso, qualquer linha em branco1.txt
corresponderá a todas as linhas2.txt
. Portanto, isso funcionará apenas em situações muito específicas.grep
notações POSIX , que são suportadas pelogrep
encontrado nas variantes Unix mais modernas. Adicione-F
(ou usefgrep
) para suprimir expressões regulares. Adicione-x
(para exato) para corresponder apenas a linhas inteiras.comm
usar os arquivos classificados?comm
pode trabalhar com arquivos arbitrariamente grandes, desde que sejam ordenados, porque ele só precisa conter três linhas na memória (acho que o GNUcomm
saberia manter apenas um prefixo, se as linhas forem realmente longas). Agrep
solução precisa manter todas as expressões de pesquisa na memória.Se os dois arquivos ainda não foram classificados, você pode usar:
e funcionará, evitando a mensagem de erro
comm: file 2 is not in sorted order
ao fazê-locomm -12 a.txt b.txt
.fonte
<(command)
não é portátil para o shell POSIX, embora funcione no Bash e em alguns outros.fonte
comm
comando como ele procura cada linha defile1
emfile2
quecomm
comparará somente se a linhan
emfile1
é igual a linhan
nofile2
.comm
simplesmente não compara a linha N no arquivo1 com a linha N no arquivo2. É perfeitamente possível gerenciar uma série de linhas inseridas em qualquer arquivo (o que equivale a excluir uma série de linhas do outro arquivo, é claro). Apenas requer que as entradas estejam em ordem classificada.comm
respostas, se alguém quiser manter a ordem. Melhor do queawk
responder se alguém não quiser duplicatas.fonte
Na versão limitada do Linux (como um QNAP (nas) em que eu estava trabalhando)):
grep -f file1 file2
pode causar alguns problemas, como foi dito por @ChristopherSchultz, e o usogrep -F -f file1 file2
foi muito lento (mais de 5 minutos - não foi concluído - mais de 2-3 segundos com o método abaixo em arquivos com mais de 20 MB)Então aqui está o que eu fiz:
Se
files.same.sorted
deve ter sido na mesma ordem que as originais, adicione esta linha pela mesma ordem que o arquivo1:ou, pela mesma ordem que o arquivo2:
fonte
Apenas para referência, se alguém ainda estiver pensando em como fazer isso para vários arquivos, consulte a resposta vinculada a Localização de linhas correspondentes em muitos arquivos.
Combinando essas duas respostas ( ans1 e ans2 ), acho que você pode obter o resultado que precisa sem classificar os arquivos:
Simplesmente salve, conceda direitos de execução (
chmod +x compareFiles.sh
) e execute-o. Ele pegará todos os arquivos presentes no diretório de trabalho atual e fará uma comparação entre todos, deixando no arquivo "matching_lines" o resultado.Coisas a serem melhoradas:
fonte
Isso deve servir.
fonte
rm -f file3.txt
se deseja excluir o arquivo; isso não relatará nenhum erro se o arquivo não existir. OTOH, não seria necessário se o seu script simplesmente ecoasse na saída padrão, deixando o usuário do script escolher para onde a saída deveria ir. Por fim, você provavelmente desejaria usar$1
e$2
(argumentos de linha de comando) em vez de nomes de arquivos fixos (file1.out
efile2.out
). Isso deixa o algoritmo: será lento. Vai lerfile2.out
uma vez para cada linhafile1.out
. Ficará lento se os arquivos forem grandes (digamos, vários kilobytes).grep -F
que lê um arquivo na memória e, em seguida, faz uma única passagem sobre o outro, evita repetidas repetições nos dois arquivos de entrada.