1
votes

faire correspondre les colonnes dans deux fichiers et modifier le fichier résultant

J'ai deux fichiers un avec 3 colonnes et un avec 4 colonnes. Ils ressemblent à ceci

​​fichier 1:

for i in `cat file 1`; do awk '{if($4=="'$i'") print $0_}'<file2 >>output; done

fichier 2:

temp1 0.1 0.2 air 0.1
temp2 0.5 0.6 .
temp3 0.6 0.3 water 0.4

Si les valeurs de la colonne 4 dans le fichier 2 correspond à la valeur de la colonne1 dans le fichier, la sortie doit être comme:

temp1 0.1 0.2 air 0.1

c'est-à-dire toutes les valeurs du fichier 2 et les deux premières colonnes du fichier 1. en cas de non-concordance la ligne entière du fichier 2 doit être imprimée telle quelle:

Donc, la sortie finale sera

temp1 0.1 0.2 air
temp2 0.5 0.6 .
temp3 0.6 0.3 water

s'il s'agissait d'une correspondance normale des valeurs de deux fichiers comme celui-ci pourraient être utilisés:

air 0.1 0.2
soil 0.9 0.7
water 0.4 0.6

cependant, le code nécessite plus que cela.

quelqu'un pourrait-il m'aider à résoudre ce problème. p>

Merci


5 commentaires

La dernière ligne ne devrait-elle pas être plutôt temp3 0,6 0,3 eau 0,4 ?


Cela semble toujours faux.


Corrigé, merci encore


Pourquoi la ligne 3 de la sortie temp3 0,6 0,3. eau 0,4 au lieu de seulement temp3 0,6 0,3 eau 0,4 ? N'utilisez jamais le script que vous avez publié car il contient plusieurs bogues et anti-modèles - si jamais vous pensez que vous en avez besoin, posez une question ici afin que nous puissions vous aider.


Aujourd'hui, je suis sur les erreurs typographiques. Mes excuses.


3 Réponses :


2
votes

Perl à la rescousse!

#!/usr/bin/perl
use warnings;
use strict;

my %F1;
open my $f1, '<', shift or die $!;
while (<$f1>) {
    my ($id, $value) = split;
    warn "Duplicate entry for $id.\n" if exists $F1{$id};
    $F1{$id} = $value;
}

open my $f2, '<', shift or die $!;
while (<$f2>) {
    my ($val0, $val1, $val2, $id) = split;
    print join ' ', $val0, $val1, $val2, $id,
        $F1{$id} x exists $F1{$id}, "\n";
}

Enregistrer sous match-cols , exécuter en tant que perl match-cols fichier1 fichier2 . p>

Il stocke les valeurs du fichier 1 dans une table de hachage, puis lit le fichier 2 ligne par ligne et affiche soit la ligne elle-même si l'id n'est pas trouvé dans la carte de hachage, soit la ligne plus les informations stockées carte de hachage.


2 commentaires

Si le deuxième fichier a sept colonnes et que la septième colonne doit être mise en correspondance. Où modifier dans la seconde moitié de votre code. Merci d'avance.


@Angelo my ($ val0, $ val1, $ val2, $ id) = split; est la partie qui analyse les colonnes



4
votes

Cela ressemble vraiment à une utilisation classique de join . L'utilitaire join est utilisé pour joindre les fichiers sur des champs spécifiques (les fichiers doivent être triés). Cette réponse n'utilise pas awk , je ne sais pas si c'est un problème.

 join -t' ' -11 -25 -a2 -o 2.1,2.2,2.3,2.4,2.5,1.2 <(<file1 sort -t' ' -k1) <(<file2 nl -w1 -s' ' | sort -t' ' -k5) | sort -t' ' -k1 | cut -d' ' -f2-

affichera:

 join -t' ' -11 -24 -a2 -o 2.1,2.2,2.3,2.4,1.2 <(<file1 sort -t' ' -k1) <(<file2 sort -t' ' -k4)

testé sur repl .

Si vos fichiers d'entrée ne sont pas triés, vous besoin de les trier au préalable sur des champs spécifiques:

temp1 0.1 0.2 air 0.1
temp2 0.5 0.6 .
temp3 0.6 0.3 water 0.4

Si vos fichiers d'entrée ne sont pas triés et que vous devez conserver l'ordre de tri du fichier 2, numérotez les lignes du fichier 2, joignez-les, triez la sortie en utilisant les numéros de ligne de file2 et supprimez ces numéros de ligne:

cat <<EOF >file1
air 0.1 0.2
soil 0.9 0.7
water 0.4 0.6
EOF
cat <<EOF >file2
temp1 0.1 0.2 air
temp2 0.5 0.6 .
temp3 0.6 0.3 water
EOF

# separator is space
# join on the first field from first file
# join on the firth field from the second file
# in case the lines are not matched, print the line from second file
# output - first output 4 fields from file 2 and second field from file 2
#          it is the same as 3 fields from file 2 and 2 fields from file 1
join -t' ' -11 -24 -a2 -o 2.1,2.2,2.3,2.4,1.2 file1 file2


2 commentaires

Cela ne fonctionne pas, il n'imprime que le contenu du deuxième fichier.


Eh bien, j'ai inclus un lien vers repl en ligne bash runner, qui permet de tester la sortie. «Cela ne fonctionne pas» est une description très vague du problème. Peut-être que vos fichiers sont séparés par des tabulations, pas des espaces, alors tous les -t '' et -d '' doivent être supprimés (ou remplacés par - t $ '\ t' ).



3
votes
$ awk 'NR==FNR{a[$1]=$2; next} {print $0 ($4 in a ? OFS a[$4] : "")}' file1 file2
temp1 0.1 0.2 air 0.1
temp2 0.5 0.6 .
temp3 0.6 0.3 water 0.4

0 commentaires