Veja o que você poderia fazer no bash simples, assumindo que os dados são exatamente como você postou. ( Warning : modifica os arquivos no local. Tenha o cuidado de fazer backups antes do teste.)
Algumas funções para gerenciar os dois primeiros arquivos:
next_id() {
file="$1"
# assumes file is sorted by id
echo $(( $(tail -n 1 $file|cut -d, -f1) + 1 ))
}
Assumindo que arquivo1 e arquivo2 estejam classificados na coluna id, isso pega a primeira parte da última linha e incrementa-a em um, gerando o próximo id.
find_or_create_id() {
file="$1"
item="$2"
# check if we already have that item
id=$(grep -m 1 ",$item$" "$file" 2> /dev/null)
if [[ $? -ne 0 ]] ; then
# generate the next id, append
id=$(next_id "$file")
echo "$id,$item" >> "$file"
else
# got it already
id=${id/,*}
fi
echo "$id"
}
Isso procura um item (vname ou dname) em um dos dois primeiros arquivos. Se for encontrado, retorne o ID existente. Caso contrário, gere o próximo id e armazene-o de volta no arquivo.
A parte principal é bem simples quando você tem as substrings certas:
while read line ; do
col1=${line/,*} # everything up to first ,
col3=${line//*,} # everything after last ,
col2=${line%,*} # everything after first ,
col2=${col2#*,} # everything before last ,
id1=$(find_or_create_id file1 "$col1")
id2=$(find_or_create_id file2 "$col2")
# don't insert duplicates
if ! grep -m 1 -q "^$id1,$id2," file3 ; then
echo "$id1,$id2,$col3" >> file3
fi
done < <(tail -n +2 file4)
Isso não será inserido no último arquivo na ordem, e as novas linhas serão adicionadas no final.
Dito isto, se algum desses arquivos não for de tamanho trivial, um banco de dados seria apropriado. Olhe para o SQLite se você não quiser um servidor de banco de dados.
Supondo que você não se importa com ids sequenciais (apenas que eles são distintos), e você colocou integer primary key autoincrement
ids para a tabela 1 e a tabela 2 (além de chaves exclusivas em vname e dname), a atualização seria como (provavelmente existem maneiras mais sutis do que a abordagem insert or ignore
):
insert or ignore into tab1(vname) select distinct vname from tab4;
insert or ignore into tab2(dname) select distinct dname from tab4;
insert or ignore into tab3(id1,id2,value)
select tab1.id, tab2.id, tab4.value
from tab4
left join tab1 on tab1.vname = tab4.vname
left join tab2 on tab2.dname = tab4.dname;
SQLite pode lidar com o "
em seu arquivo muito bem.
.separator ,
.import fileX tabX
faz o Right Thing ™, pelo menos com as amostras que você tem lá.
Esquema simples:
create table tab1 (id integer primary key autoincrement, vname text);
create unique index tab1_vname on tab1(vname);
create table tab2 (id integer primary key autoincrement, dname text);
create unique index tab2_dname on tab2(dname);
create table tab3 (id1 int, id2 int, value text,
constraint tab3_pk primary key(id1, id2));
create table tab4 (vname text, dname text, value text);