Fonction vlookup dans unix

Comment faire quelque chose de similaire à la fonction vlookup d'Excel sous Unix?

extrait du site Web du bureau, VLOOKUP

Le V dans VLOOKUP est vertical. Utilisez VLOOKUP au lieu de HLOOKUP lorsque vos valeurs de comparaison sont situées dans une colonne à gauche des données que vous souhaitez searchr.

Syntaxe VLOOKUP (lookup_value, table_array, col_index_num, range_lookup)

Lookup_value Valeur à searchr dans la première colonne du tableau. Lookup_value peut être une valeur ou une reference. Si lookup_value est plus petite que la plus petite valeur de la première colonne de table_array, VLOOKUP renvoie la valeur d'erreur # N / A.

Table_array Deux colonnes ou plus de données. Utilisez une reference à une plage ou un nom de plage. Les valeurs de la première colonne de table_array sont les valeurs recherchées par lookup_value. Ces valeurs peuvent être du text, des nombres ou des valeurs logiques. Les majuscules et minuscules sont équivalentes.

Col_index_num Numéro de colonne dans table_array à partir duquel la valeur correspondante doit être renvoyée. Un col_index_num de 1 renvoie la valeur dans la première colonne de table_array; un col_index_num de 2 renvoie la valeur dans la deuxième colonne dans table_array, et ainsi de suite. Si col_index_num est:

Moins de 1, VLOOKUP renvoie la valeur #VALUE! valeur d'erreur. Plus grand que le nombre de colonnes dans table_array, VLOOKUP renvoie le #REF! valeur d'erreur.

Range_lookup Valeur logique qui spécifie si vous voulez que VLOOKUP trouve une correspondance exacte ou une correspondance approximative:

Fichier1:

1GR_P1:001PI :040VG_L1 :001PO_L3 1JPI_P1:001PO_L1 1JPI_P1:001PO_L2 

Fichier2:

 1JPI_P1:001PO_L1 1401UC 1JPI_P1:001PO_L2 1401UC 1HIK_P2:001ER 1402UC 1GR_P1:001PI 1402UC 

Fichier de sortie3:

 1GR_P1:001PI 1402UC :040VG_L1 NA :001PO_L3 NA 1JPI_P1:001PO_L1 1401UC 1JPI_P1:001PO_L2 1401UC 

Il n'y a pas de fonction générale qui fera un vlookup comme une fonction générale dans Unix. Au lieu de cela, vous donnez des «briques» à partir desquelles vous pouvez créer des solutions aux problèmes dans une approche plus personnalisée. Ces "briques" sont des outils tels que grep , awk et sed entre autres.

Un des outils, awk pourrait être utilisé comme suit:

vlookup.awk

 FNR==NR{ a[$1]=$2 next } { if ($1 in a) {print $1, a[$1]} else {print $1, "NA"} } 

Exemple

 $ awk -f vlookup.awk file2 file1 1GR_P1:001PI 1GR_P1:001PI :040VG_L1 NA :001PO_L3 NA 1JPI_P1:001PO_L1 1JPI_P1:001PO_L1 1JPI_P1:001PO_L2 1JPI_P1:001PO_L2 

Vous pouvez utiliser la command de column pour nettoyer la sortie:

 $ awk -f vlookup.awk file2 file1 | column -t 1GR_P1:001PI 1GR_P1:001PI :040VG_L1 NA :001PO_L3 NA 1JPI_P1:001PO_L1 1JPI_P1:001PO_L1 1JPI_P1:001PO_L2 1JPI_P1:001PO_L2 

Détails

Le script awk ci-dessus prend tout le contenu de file2 dans un tableau qui est indexé en utilisant la valeur comme key.

 a[$1]=$1 

Une fois que file2 a été lu dans le tableau a , file1 est ensuite passé par une ligne à la fois et une décision est prise. Si la valeur de la première colonne du file1 est présente dans le tableau a , la valeur correspondante dans la colonne 2 du file2 est imprimée avec la colonne 1 du file 1. Si elle n'est pas présente, le message "NA" est imprimé .

Pour les exemples de données spécifiques que vous avez fournis, les éléments suivants devraient fonctionner. Il charge le champ 2 de File2 dans un tableau indexé par le champ 1. File1 est ensuite boukey et les correspondances de tableau ou NA sont imprimées

 awk 'NR == FNR{a[$1] = $2;next}; {print $1, $1 in a?a[$1]: "NA"}' File2 File1 

Si vous cherchez quelque chose qui fonctionne à partir de la command line, jetez un oeil à awk . C'est un programme très populaire utilisé pour toutes sortes d'opérations d'parsing. http://en.wikipedia.org/wiki/AWK

En outre, il est difficile de mentionner l'parsing du text dans UNIX sans mentionner grep . grep est utilisé pour le text correspondant à la regex. Bien que non nécessaire pour cette application particulière, il sera finalement utile si vous faites beaucoup d'parsing de text. http://en.wikipedia.org/wiki/Grep

L' colrm colonnes de text colrm peut être coupée à partir d'un stream. Cela peut être utile lorsque vous rencontrez des problèmes pour isoler le text avec awk .

sed est ce que vous voudrez utiliser si le text à parsingr est très long ou si awk n'est pas capable d'accomplir facilement ce que vous voulez. Sed sur Wikipédia

Je suis sûr qu'il me manque des dizaines mais tout ce dont vous aurez besoin pour cet exemple est awk donc vous êtes prêt.

La command POSIX join(1) fait quelque chose de très similaire à VLOOKUP() , avec la mise en garde que les files d'input doivent déjà être sortingés sur les colonnes à joindre .

 $ sort file1 > sfile1 $ sort file2 > sfile2 $ join -a1 sfile1 sfile2 1GR_P1:001PI 1402UC 1JPI_P1:001PO_L1 1401UC 1JPI_P1:001PO_L2 1401UC :001PO_L3 :040VG_L1 

Malheureusement, votre exemple ne montre pas vraiment comment fonctionne la join , puisque le file1 contient une seule colonne.

Pour get exactement la sortie que vous voulez, vous pouvez écrire un script simple en utilisant des arrays associatifs, en utilisant awk par exemple, comme d'autres l'ont suggéré.

Essayez un mélange de awk et de redis (un magasin de valeurs-keys NoSQL open source extrêmement rapide.) Voir http://redis.io pour plus de détails.

Utilisez awk pour parsingr vos 2 files afin de générer vos commands de redis.

Pipe le résultat des 2 scripts awk dans bash pour les exécuter. C'est tout 🙂

Pas à pas:

Générez vos redis "SET" déclarations en analysant "File2" comme ceci:

 awk '{print "redis-cli SET KEY:" $1 " \"" $2"\""}' File2 redis-cli SET KEY:1JPI_P1:001PO_L1 "1401UC" redis-cli SET KEY:1JPI_P1:001PO_L2 "1401UC" redis-cli SET KEY:1HIK_P2:001ER "1402UC" redis-cli SET KEY:1GR_P1:001PI "1402UC" 

Pipe vos redis généré "SET" déclarations dans bash pour les exécuter:

 awk '{print "redis-cli SET KEY:" $1 " \"" $2"\""}' File2 |\ bash OK OK OK OK 

Générez vos redis "GET" des déclarations en analysant "File1" comme ceci:

 awk '{print "printf \"" $1 " \" && redis-cli GET KEY:" $1}' File1 printf "1GR_P1:001PI " && redis-cli GET KEY:1GR_P1:001PI printf ":040VG_L1 " && redis-cli GET KEY::040VG_L1 printf ":001PO_L3 " && redis-cli GET KEY::001PO_L3 printf "1JPI_P1:001PO_L1 " && redis-cli GET KEY:1JPI_P1:001PO_L1 printf "1JPI_P1:001PO_L2 " && redis-cli GET KEY:1JPI_P1:001PO_L2 

Maintenant, redisez la requête en mettant vos instructions redis "GET" générées ci-dessus dans bash:

 awk '{print "printf \"" $1 " \" && redis-cli GET KEY:" $1}' File1 |\ bash 1GR_P1:001PI "1402UC" :040VG_L1 (nil) :001PO_L3 (nil) 1JPI_P1:001PO_L1 "1401UC" 1JPI_P1:001PO_L2 "1401UC" 

Attention, vous devez éviter les guillemets doubles dans vos strings avec des barres obliques inversées pour éviter de redissortingbuer les erreurs d'import (voir la réponse de slm sur Comment modifier cette solution Perl pour qu'elle substitue des guillemets doubles entre guillemets simples? ). Vous pouvez également utiliser des guillemets simples pour encapsuler vos valeurs pour l'import dans redis, si vos valeurs contiennent beaucoup de guillemets doubles.

HTH

bernie