join file1 file2
Por padrão, ele usará a coluna 1 para cada arquivo e omitirá as linhas que estiverem faltando nelas, que é o que você deseja. Além disso, os arquivos precisam ser classificados, o que já é o caso.
Eu tenho dois grandes arquivos de 400.000 linhas. Eu quero comparar a coluna 1 do segundo arquivo com a coluna 1 do primeiro arquivo recursivamente. Se combinarem, gostaria de imprimir a linha inteira. É um arquivo classificado.
file 1:
name values
aaa 10
aab acc
aac 30
aac abc
file2:
aaa
aac
aac
aad
como o arquivo contém 400.000 linhas, leva tempo para ser processado.
Minha solução atual é assim
#!/bin/ksh
while read line
do
var='echo $line '
grep "$var" file1 >> /dev/null
if [ $? -eq 0 ]
then
grep "$var" file1 >> present
else
echo " $line missing " > missing
fi
done < "file2"
Como estou usando grep
aqui, o valor pode estar presente em algum lugar no arquivo1 que não seja a coluna pretendida1, não quero que isso aconteça.
Minha solução esperada:
perl
com ponteiro de arquivo compara duas colunas dos arquivos. Se a cadeia corresponder, imprima-a. Senão, se a coluna 1 do primeiro arquivo for maior que a do segundo arquivo, incremente o arquivo 2 AND COMPARE. Se for VICE VERSA, incremente a coluna 1 do arquivo 1 e compare. join file1 file2
Por padrão, ele usará a coluna 1 para cada arquivo e omitirá as linhas que estiverem faltando nelas, que é o que você deseja. Além disso, os arquivos precisam ser classificados, o que já é o caso.
É algo parecido com o que você está procurando? Eu uso cut
para dividir a lista em matrizes, cada uma contendo uma coluna. Isso pressupõe que as colunas são delimitadas por um caractere de tabulação. Você pode alterar os usos de corte do delimitador especificando a opção -d
. Para dividir no sublinhado: cut -d '_'
.
#!/bin/bash
FILE1='somefile'
FILE2='someotherfile'
# File 1, column 1
f1c1=($(cut -f1 -s $FILE1))
# File 1, column 2
#f1c2=($(cut -f2 -s $FILE1))
# File 2, column 1
f2c1=($(cut -f1 -s $FILE2))
# File 2, column 2
#f2c2=($(cut -f2 -s $FILE2))
# Looping through all items in file 1 column 1
for x in "${f1c1[@]}"
do
# For each item in f1c1, check all items in f2c1 for a match
for y in "${f2c1[@]}"
do
if [[ $x == $y ]]
then
# The items matched!
echo $x
# Breaking out of the loop (no need to check for more than one
# match, right?)
break
fi
done
done
Espero que isso ajude ou, pelo menos, você fique mais perto de uma solução.
Se o número de elementos exclusivos em file2
não for muito grande, uma solução viável pode ser a abordagem clássica de processar ambos os arquivos com awk
, primeiro criando uma matriz do único elementos na coluna 1 de file2
e, em seguida, testando a coluna 1 de file1
para associação na matriz, ou seja,
awk 'FNR==NR {a[$1]++}; FNR!=NR && a[$1]' file2 file1
Uma abordagem equivalente usando arrays associativos bash 4+
pode ser algo como
#!/bin/bash
declare -A a
while read col1 _ ; do
((a[$col1]++))
done < file2
while IFS= read -r line; do
# compare only with 1st column of second file
read -r col1 _ <<< "$line"
[[ -n "${a[$col1]}" ]] && printf "$line\n"
done < file1