Supondo que os arquivos de entrada são classificados em ordem alfabética no campo de junção (como estão em sua amostra):
join -e0 -a1 -a2 -o 0,1.2,2.2 file1 file2 | tr ' ' ,
Arquivo1:
00:00 274
00:04 476
00:05 450
00:06 499
00:07 373
00:08 206
00:09 471
00:10 154
Arquivo2:
00:00 183
00:01 60
00:02 344
00:03 540
00:04 450
00:07 348
00:09 473
00:10 203
Saída desejada:
00:00,274,183
00:01,0,60
00:02,0,344
00:03,0,540
00:04,476,450
00:05,450,0
00:06,499,0
00:07,373,348
00:08,206,0
00:09,471,473
00:10,154,203
A coluna 1 de cada arquivo será verificada e, se for o mesmo, os valores serão unidos à saída. Por favor, observe o valor "0" para aqueles conteúdos que não estão presentes em nenhum arquivo. Além disso, isso será usado para combinar o conteúdo de 6 arquivos.
Supondo que os arquivos de entrada são classificados em ordem alfabética no campo de junção (como estão em sua amostra):
join -e0 -a1 -a2 -o 0,1.2,2.2 file1 file2 | tr ' ' ,
Bash
#!/bin/bash
file1=t1
file2=t2
while read line
do
v1=$(grep "${line}" $file1|| echo 0)
v2=$(grep "${line}" $file2|| echo 0)
echo ${line},${v1#* },${v2#* }
done < <(awk '!a[$1]++{print $1| "sort"}' $file1 $file2)
Resultado
00:00,274,183
00:01,0,60
00:02,0,344
00:03,0,540
00:04,476,450
00:05,450,0
00:06,499,0
00:07,373,348
00:08,206,0
00:09,471,473
00:10,154,203
Infelizmente join
não adiciona os arquivos que estão faltando linhas. A opção -e
apenas adiciona o argumento a linhas com a chave. Você pode extrair as chaves, adicioná-las a cada arquivo, se ainda não estiver lá com as ferramentas padrão, e então usar join, mas então é melhor escrever um programa pequeno, por exemplo, em Python:
import sys
default = ['0'] * len(sys.argv[1:])
r = {}
for idx, fn in enumerate(sys.argv[1:]):
for line in open(fn):
c1, c2 = line.split()
r.setdefault(c1, default[:])[idx] = c2
for c1 in sorted(r): # print output
print("{},{}".format(c1, ','.join(r[c1])))
salve como join.py
e execute com
python join.py file1 file2 [file3 ....]
i.e. você pode adicionar quantos arquivos você tiver na linha de comando
Isso dá exatamente a saída que você solicitou (exceto que você trocou valores por 00:02 e 00:03)
Se a ordem das linhas não é importante, ou você não se importa em ter a entrada e a saída classificadas (o que não parece ser um problema considerando a entrada que você deu), você pode usar join
duas vezes:
(
join -a 1 -e "0" -o "1.1 1.2 2.2" file1 file2
join -a 2 -e "0" -o "2.1 1.2 2.2" file1 file2
) | sort -u | sed "s/ /,/g"
A opção -a
reproduz linhas não correspondentes do primeiro ( -a1
) ou do segundo ( -a2
), -e "0"
usa zero como um substituto para as linhas ausentes do outro arquivo, -o
descreve o formato das linhas de saída como uma lista de valores FILE.FIELD (consulte join(1)
man page). sort -u
remove duplicatas de linhas. O% final sed
substitui todos espaços em cada linha por vírgulas.
Ou, se você for bastante aventureiro, descobrirá que uma vez é suficiente com as opções certas . Obrigado Stephane!
Versão mais simples.
FNR==NR{ a[$1]=$2;next; }
{
if ($1 in a){
a[$1] = ( $1 "," a[$1] "," $2 )
}else{
a[$1] = ( $1 ",0," $2 )
}
} END {
for ( x in a ){
if ( match(a[x],x) ){print a[x]}else{ print x "," a[x] ",0"}
}
}
awk -f new.awk 1.txt 2.txt | sort
Aqui está o awk. Não tenho certeza de como classificar rapidamente uma matriz associativa, apenas canalize-a para classificar. Trabalho.
BEGIN{st=0}
{if(st==0){
cur=FILENAME; st++}
if((st==1)&&(cur==FILENAME)){
a[$1]=$2;
}
else{ b[$1]=$2 }
}END{
for(i in b){
if(a[i]){
a[i]=a[i] "," b[i];
}else{ a[i]="0," b[i] } }
for(i in a){
if (b[i]){
print i "," a[i]
}else{
print i "," a[i] ",0"
}
}
}
awk -f test.awk 1.txt 2.txt | sort
00:00,274,183
00:01,0,60
00:02,0,344
00:03,0,540
00:04,476,450
00:05,450,0
00:06,499,0
00:07,373,348
00:08,206,0
00:09,471,473
00:10,154,203
Experimente o seguinte script Perl
#!/usr/bin/perl
$filenum = $#ARGV;
if ($filenum < 0) {
print "No arguments\n";
exit(1);
}
for (my $i=0; $i<=$filenum; $i++) {
open($fh,"<","$ARGV[$i]") || die "Could not open $ARGV[$i]\n";
while (<$fh>) {
($a,$b) = split/\s/;
@{$myhash{$a}}[$i]=$b;
}
close($fh);
}
foreach my $x ( sort keys %myhash) {
print "$x";
for (my $i=0; $i<=$filenum; $i++) {
if (defined @{$myhash{$x}}[$i]) {
print ",@{$myhash{$x}}[$i]";
}
else {
print ",0";
}
}
print "\n";
}
salve-o em um arquivo myscript.pl
e execute-o como:
perl myscript.pl file1 file2 ...
Espero que ajude.
Tags text-processing join columns