Rechercher / lire un autre fichier sur awk en fonction du contenu du fichier actuel, est-ce possible?

StackOverflow https://stackoverflow.com/questions/144321

Question

Je traite un très gros fichier avec (GNU) awk , (les autres outils disponibles sont: les outils du shell Linux, une ancienne version (> 5.0) de Perl, mais je ne peux pas installer de modules. ).

Mon problème: si un champ1, un champ2, un champ3 contient X, Y, ZI doit rechercher un fichier dans un autre répertoire qui contient champ4 et champ5 sur une ligne, et insérer des données du fichier trouvé dans la sortie actuelle.

Exemple:

Ligne de fichier actuelle:

f1 f2 f3 f4 f5
X  Y  Z  A  B

Je dois maintenant rechercher un autre fichier (dans un autre répertoire) contenant par exemple

.
f1 f2 f3 f4
A  U  B  W

Et écrivez dans STDOUT $ 0 à partir du fichier d'origine et f2 et f3 à partir du fichier trouvé, puis traitez la ligne suivante du fichier d'origine.

Est-il possible de le faire avec awk ?

Était-ce utile?

La solution

Permettez-moi de commencer par dire que la description de votre problème n'est pas vraiment utile. La prochaine fois, soyez juste plus précis: vous manquerez peut-être de solutions bien meilleures.

Donc, d'après votre description, vous avez deux fichiers contenant des données séparées par des espaces. Dans le premier fichier, vous souhaitez faire correspondre les trois premières colonnes à certains modèles de recherche. Si vous le trouvez, vous souhaitez rechercher toutes les lignes d'un autre fichier contenant les quatrième et cinquième colonnes de la ligne correspondante du premier fichier. À partir de ces lignes, vous devez extraire les deuxième et troisième colonnes, puis imprimer la première colonne du premier fichier et les deuxième et troisième du deuxième fichier. Ok, voici:

#!/usr/bin/env perl -nwa
use strict;
use File::Find 'find';
my @search = qw(X Y Z);

# if you know in advance that the otherfile isn't
# huge, you can cache it in memory as an optimization.

# with any more columns, you want a loop here:
if ($F[0] eq $search[0]
    and $F[1] eq $search[1]
    and $F[2] eq $search[2])
{
  my @files;
  find(sub {
      return if not -f 

Permettez-moi de commencer par dire que la description de votre problème n'est pas vraiment utile. La prochaine fois, soyez juste plus précis: vous manquerez peut-être de solutions bien meilleures.

Donc, d'après votre description, vous avez deux fichiers contenant des données séparées par des espaces. Dans le premier fichier, vous souhaitez faire correspondre les trois premières colonnes à certains modèles de recherche. Si vous le trouvez, vous souhaitez rechercher toutes les lignes d'un autre fichier contenant les quatrième et cinquième colonnes de la ligne correspondante du premier fichier. À partir de ces lignes, vous devez extraire les deuxième et troisième colonnes, puis imprimer la première colonne du premier fichier et les deuxième et troisième du deuxième fichier. Ok, voici:

<*>

Contrairement à la solution d'un autre poster qui contient beaucoup d'appels système, cela ne revient pas du tout au shell et devrait donc être très rapide.

; # verbatim search for the columns in the file name. # I'm still not sure what your file-search criteria are, though. push @files, $File::Find::name if /\Q$F[3]\E/ and /\Q$F[4]\E/; # alternatively search for the combination: #push @files, $File::Find::name if /\Q$F[3]\E.*\Q$F[4]\E/; # or search *all* files in the search path? #push @files, $File::Find::name; }, '/search/path' ) foreach my $file (@files) { open my $fh, '<', $file or die "Can't open file '$file': $!"; while (defined(

Permettez-moi de commencer par dire que la description de votre problème n'est pas vraiment utile. La prochaine fois, soyez juste plus précis: vous manquerez peut-être de solutions bien meilleures.

Donc, d'après votre description, vous avez deux fichiers contenant des données séparées par des espaces. Dans le premier fichier, vous souhaitez faire correspondre les trois premières colonnes à certains modèles de recherche. Si vous le trouvez, vous souhaitez rechercher toutes les lignes d'un autre fichier contenant les quatrième et cinquième colonnes de la ligne correspondante du premier fichier. À partir de ces lignes, vous devez extraire les deuxième et troisième colonnes, puis imprimer la première colonne du premier fichier et les deuxième et troisième du deuxième fichier. Ok, voici:

<*>

Contrairement à la solution d'un autre poster qui contient beaucoup d'appels système, cela ne revient pas du tout au shell et devrait donc être très rapide.

= <$fh>)) { chomp; # order of fields doesn't matter per your requirement. my @cols = split ' ',

Permettez-moi de commencer par dire que la description de votre problème n'est pas vraiment utile. La prochaine fois, soyez juste plus précis: vous manquerez peut-être de solutions bien meilleures.

Donc, d'après votre description, vous avez deux fichiers contenant des données séparées par des espaces. Dans le premier fichier, vous souhaitez faire correspondre les trois premières colonnes à certains modèles de recherche. Si vous le trouvez, vous souhaitez rechercher toutes les lignes d'un autre fichier contenant les quatrième et cinquième colonnes de la ligne correspondante du premier fichier. À partir de ces lignes, vous devez extraire les deuxième et troisième colonnes, puis imprimer la première colonne du premier fichier et les deuxième et troisième du deuxième fichier. Ok, voici:

<*>

Contrairement à la solution d'un autre poster qui contient beaucoup d'appels système, cela ne revient pas du tout au shell et devrait donc être très rapide.

; my %seen = map {(

Permettez-moi de commencer par dire que la description de votre problème n'est pas vraiment utile. La prochaine fois, soyez juste plus précis: vous manquerez peut-être de solutions bien meilleures.

Donc, d'après votre description, vous avez deux fichiers contenant des données séparées par des espaces. Dans le premier fichier, vous souhaitez faire correspondre les trois premières colonnes à certains modèles de recherche. Si vous le trouvez, vous souhaitez rechercher toutes les lignes d'un autre fichier contenant les quatrième et cinquième colonnes de la ligne correspondante du premier fichier. À partir de ces lignes, vous devez extraire les deuxième et troisième colonnes, puis imprimer la première colonne du premier fichier et les deuxième et troisième du deuxième fichier. Ok, voici:

<*>

Contrairement à la solution d'un autre poster qui contient beaucoup d'appels système, cela ne revient pas du tout au shell et devrait donc être très rapide.

=>1)} @cols; if ($seen{$F[3]} and $seen{$F[4]}) { print join(' ', $F[0], @cols[1,2]), "\n"; } } close $fh; } } # end if matching line

Contrairement à la solution d'un autre poster qui contient beaucoup d'appels système, cela ne revient pas du tout au shell et devrait donc être très rapide.

Autres conseils

C'est le type de travail qui m'a amené à passer de awk à perl en premier lieu. Si vous voulez accomplir cela, vous trouverez peut-être plus facile de créer un script shell qui crée un ou plusieurs scripts awk à interroger puis à mettre à jour par étapes distinctes.

(J'ai écrit une telle bête pour lire / mettre à jour des fichiers de style Windows - c'est moche. J'aurais aimé pouvoir utiliser perl.)

Je vois souvent la restriction "je ne peux utiliser aucun module Perl", et lorsque ce n'est pas une question de devoir, c'est souvent simplement par manque d'informations. Oui, même si vous pouvez utiliser CPAN , vous apprendrez à installer les modules CPAN localement sans privilèges root. . Une autre solution consiste simplement à prendre le code source d’un module CPAN et à le coller dans votre programme.

Rien de tout cela n’aide s’il existe d’autres restrictions non spécifiées, telles que le manque d’espace disque qui empêche l’installation de (trop) de fichiers supplémentaires.

Cela semble fonctionner pour certains fichiers de test que j'ai configurés pour correspondre à vos exemples. Impliquer perl de cette manière (interposé avec grep) va probablement faire beaucoup mal à la performance, bien que ...

## perl code to do some dirty work

for my $line (`grep 'X Y Z' myhugefile`) {
    chomp $line;
    my ($a, $b, $c, $d, $e) = split(/ /,$line);
    my $cmd = 'grep -P "' . $d . ' .+? ' . $e .'" otherfile';
    for my $from_otherfile (`$cmd`) {
        chomp $from_otherfile;
        my ($oa, $ob, $oc, $od) = split(/ /,$from_otherfile);
        print "$a $ob $oc\n";
    }
}

EDIT: utilisez la solution de tsee (ci-dessus), elle est beaucoup plus réfléchie.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top