File1.txt
item1 carA
item2 carB
item3 carC
item4 platD
item5 carE
File2.txt
carA platA
carB platB
carC platC
carE platE
Sortie recherchée:
item1 platA
item2 platB
item3 platC
item4 platD
item5 platE
Comment puis-je le faire?
La réponse ci-dessous est basée sur un Q & A similaire à SO avec quelques modifications pertinentes:
$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($2 in dict) ? dict[$2] : $2}1' file2.txt file1.txt
item1 platA
item2 platB
item3 platC
item4 platD
item5 platE
L'idée est de créer une carte de hachage avec index et de l'utiliser comme dictionnaire.
Pour la deuxième question que vous avez posée dans votre commentaire (), que devrait-on changer si la deuxième colonne de file1.txt
sera la sixième colonne ):
Si le fichier d'entrée ressemble à file1b.txt
:
item1 A5 B C D carA
item2 A4 1 2 3 carB
item3 A3 2 3 4 carC
item4 A2 4 5 6 platD
item5 A1 7 8 9 carE
La commande suivante le fera:
$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($6 in dict) ? dict[$6] : $6;$3="";$4="";$5="";$6=""}1' file2.txt file1b.txt
item1 platA
item2 platB
item3 platC
item4 platD
item5 platE
Je sais que vous avez dit awk
, mais il existe une commande join
à cette fin ...
{
join -o 1.1,2.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt)
join -v 1 -o 1.1,1.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt)
} | sort -k 1
Cela serait suffisant avec la première commande join
s'il n'y avait pas cette ligne:
item4 platD
La commande dit essentiellement: join en fonction de la deuxième colonne du premier fichier (-1 2
) et de la première colonne du deuxième fichier (-2 1
), et affiche la première colonne du premier fichier et la deuxième colonne du deuxième fichier (-o 1.1,2.2
). Cela ne montre que les lignes qui sont liées. La deuxième commande de jointure dit à peu près la même chose, mais elle dit de montrer les lignes du premier fichier qui ne pouvaient pas être appariées (-v 1
) et d'afficher la première colonne du premier fichier et la deuxième colonne du premier fichier (-o 1.1,1.2
). Ensuite, nous trions la sortie des deux combinés. sort -k 1
signifie un tri basé sur la première colonne, et sort -k 2
signifie un tri basé sur la seconde. Il est important de trier les fichiers en fonction de la colonne join avant de les transmettre à join
.
Maintenant, j’ai écrit le tri à deux reprises, parce que je n’aime pas encombrer mes répertoires de fichiers si je peux l’aider. Toutefois, comme l’a dit David Foerster, selon la taille des fichiers, vous pouvez trier les fichiers et les enregistrer d’abord pour ne pas avoir à attendre pour les trier deux fois. Pour donner une idée des tailles, voici le temps qu'il faut pour trier 1 million et 10 millions de lignes sur mon ordinateur:
$ Ruby -e '(1..1000000).each {|i| puts "item#{i} plat#{i}"}' | shuf > 1million.txt
$ Ruby -e '(1..10000000).each {|i| puts "item#{i} plat#{i}"}' | shuf > 10million.txt
$ head 10million.txt
item530284 plat530284
item7946579 plat7946579
item1521735 plat1521735
item9762844 plat9762844
item2289811 plat2289811
item6878181 plat6878181
item7957075 plat7957075
item2527811 plat2527811
item5940907 plat5940907
item3289494 plat3289494
$ TIMEFORMAT=%E
$ time sort 1million.txt >/dev/null
1.547
$ time sort 10million.txt >/dev/null
19.187
Cela représente 1,5 seconde pour 1 million de lignes et 19 secondes pour 10 millions de lignes.