GNU/Linux >> Tutoriels Linux >  >> Linux

Fusionner par date plusieurs fichiers journaux qui incluent également des lignes non datées (par exemple, des traces de pile)

Difficile. Bien qu'il soit possible d'utiliser date et les tableaux bash, c'est vraiment le genre de chose qui bénéficierait d'un vrai langage de programmation. En Perl par exemple :

$ perl -ne '$d=$1 if /(.+?),/; $k{$d}.=$_; END{print $k{$_} for sort keys(%k);}' log*
01:02:03.6497,2224,0022 foo
foo1
2foo
foo3
01:03:03.6497,2224,0022 FOO
FOO1
2FOO
FOO3
01:04:03.6497,2224,0022 bar
1bar
bar2
3bar

Voici la même chose non condensée dans un script commenté :

#!/usr/bin/env perl

## Read each input line, saving it 
## as $_. This while loop is equivalent
## to perl -ne 
while (<>) {
    ## If this line has a comma
    if (/(.+?),/) {
        ## Save everything up to the 1st 
        ## comma as $date
        $date=$1;
    }
    ## Add the current line to the %k hash.
    ## The hash's keys are the dates and the 
    ## contents are the lines.
    $k{$date}.=$_;
}

## Get the sorted list of hash keys
@dates=sort(keys(%k));
## Now that we have them sorted, 
## print each set of lines.
foreach $date (@dates) {
    print "$k{$date}";
}

Notez que cela suppose que toutes les lignes de date et uniquement les lignes de date contiennent une virgule. Si ce n'est pas le cas, vous pouvez utiliser ceci à la place :

perl -ne '$d=$1 if /^(\d+:\d+:\d+\.\d+),/; $k{$d}.=$_; END{print $k{$_} for sort keys(%k);}' log*

L'approche ci-dessus doit conserver l'intégralité du contenu des fichiers en mémoire. Si c'est un problème, en voici un qui n'en a pas :

$ perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/' log* | 
    sort -n | perl -lne 's/\0/\n/g; printf'
01:02:03.6497,2224,0022 foo
foo1
2foo
foo3    
01:03:03.6497,2224,0022 FOO
FOO1
2FOO
FOO3    
01:04:03.6497,2224,0022 bar
1bar
bar2
3bar

Celui-ci place simplement toutes les lignes entre les horodatages successifs sur une seule ligne en remplaçant les nouvelles lignes par \0 (si cela peut être dans vos fichiers journaux, utilisez n'importe quelle séquence de caractères dont vous savez qu'elle n'y sera jamais). Ceci est passé à sort puis tr pour récupérer les lignes.

Comme l'a très correctement souligné l'OP, toutes les solutions ci-dessus doivent être recourues et ne tiennent pas compte du fait que les fichiers peuvent être fusionnés. En voici un qui le fait mais qui contrairement aux autres ne fonctionnera que sur deux fichiers :

$ sort -m <(perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/' log1) \
            <(perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/' log2) | 
    perl -lne 's/[\0\r]/\n/g; printf'

Et si vous enregistrez la commande perl en tant qu'alias, vous pouvez obtenir :

$ alias a="perl -pe 's/\n/\0/; s/^/\n/ if /^\d+:\d+:\d+\.\d+/'"
$ sort -m <(a log1) <(a log2) | perl -lne 's/[\0\r]/\n/g; printf'

Linux
  1. 20 fichiers journaux Linux situés dans le répertoire /var/log

  2. Comment supprimer plusieurs fichiers à la fois dans Bash sous Linux ?

  3. Compter les lignes dans les fichiers volumineux

  4. syntaxe du fichier de configuration logrotate - plusieurs entrées génériques possibles ?

  5. Renommer plusieurs fichiers pour supprimer le suffixe commun des noms de fichiers

Comment fusionner plusieurs fichiers PDF en un seul PDF sous Linux

Comment joindre/fusionner plusieurs fichiers audio en un seul sous Linux

Dd :plusieurs fichiers d'entrée ?

Fichiers journaux Linux

10 exemples impressionnants pour afficher d'énormes fichiers journaux sous Unix

3 méthodes pour afficher la sortie tail -f de plusieurs fichiers journaux dans un terminal