J'ai un fichier journal de 8 Go (journal de production Rails). J'ai besoin de le couper entre certaines dates (lignes). Quelle commande pourrais-je utiliser pour ce faire?
sed
le ferez facilement.
J'ai un fichier journal de 8 Go (journal de production Rails). J'ai besoin de le couper entre certaines dates (lignes). Quelle commande pourrais-je utiliser pour ce faire?
sed
le ferez facilement.
Réponses:
Quelque chose comme
sed '1,/last date prior to chunk/d;/first date after chunk/,$d' logfile | tee cut-log | less
tee cut-log
vous permet de voir à l'écran ce qui est mis dans le fichier cut-log
.
ÉDITER:
Pour satisfaire les normes rigoureuses de fred.bear, voici une solution sed (bien que sans doute la solution awk soit beaucoup plus jolie):
b=BB; e=EE ;echo -e "AA\nAA\nBB\nBB\nCC\nCC\nDD\nDD\nEE\nEE\nFF\nFF" | sed -n ":b;/$b/b p;n;b b;:p;p;n;/$e/b e;b p;:e;p;n;/$e/b e;q"
sed
peut correspondre awk
à la vitesse, et c'était en fait un peu plus rapide.
Pour tout imprimer entre FOO et BAR inclus, essayez:
$ sed -n '/FOO/,/BAR/p' file.txt
Cela fera ce que vous voulez ...
Les dates d'inclusion et d'exclusion sont affichées.
# set Test args
set 2011-02-24 2011-02-26 "junk"
from="$1"
till="$2"
file="$3"
# EITHER ==== +++++++++
# Ouptut lines between two parameter dates INCLUDING the parameter dates
awk -v from=$from -v till=$till '
($2 >= from) && ($2 <= till) { print $0 ; next }
($2 > till) { exit }' "$file"
# OR ======== ---------
# Ouptut lines between two parameter dates EXCLUDING the parameter dates
awk -v from=$from -v till=$till '
($2 > from) && ($2 < till) { print $0 ; next }
($2 >= till) { exit }' "$file"
Il teste une date (triée) dans le champ 2 ... Voici un exemple des données de test
98 2011-02-05 xxxx
99 2011-02-05 xxxx
100 2011-02-06 xxxx
101 2011-02-06 xxxx
Et voici le générateur de données de test .
awk -v from="$from" -v till="$till" '($2 >= from) { if ($2 <= till) { print } else { exit }' "$file"
if
instruction supplémentaire au total (pas même 1 par ligne), c'est-à-dire. le flux logique est effectivement le même, et la différence de temps d'exécution serait comptée en nanosecondes .... La seule raison pour laquelle je n'ai pas utilisé "else" est que c'est effectivement mon tout premier awk
script (à part un jour 4 ans il y a quand j'ai joué avec quelques exemples) ... et c'est le premier mécanisme de branche réalisable que j'ai trouvé ... (et comme mentionné. c'est tout aussi rapide) .. J'utilise généreusement sed
Tryq
Si dans votre fichier journal vous avez les dates dans ce format YYYY-MM-DD
, alors, pour trouver toutes les entrées pour disons, 2011-02-10, vous pouvez faire:
grep 2011-02-10 log_file
Maintenant, disons, si vous voulez trouver les entrées pour 2011-02-10 et 2011-02-11, utilisez à nouveau grep
mais avec plusieurs modèles:
grep -E '2011-02-10|2011-02-11' log_file
grep
recherchera tout le fichier, même si la plage de dates est au début du fichier. En moyenne, cela double le temps de recherche, par rapport à "exit-after-last-item-in-range" ... Je ne prends la peine de le mentionner qu'en raison de la taille de fichier de 8 Go mentionnée dans la question, Votre les résultats de temps de grep sont presque identiques à l'exemple sed ici (1min 58sec). Voici le lien vers mes résultats de tests de temps: paste.ubuntu.com/573477
Travailler avec cette taille de fichiers est toujours difficile.
Un moyen d'aller de l'avant pourrait être de diviser ce fichier en deux petits, pour ce faire, vous pouvez utiliser la commande de fractionnement.
split -d -l 50000 ToBigFile.data file_
Même si elle est divisée, vous pouvez toujours travailler avec le fichier comme s'il s'agissait d'une boucle bash for
for f in `ls file_*`; do cat $f; done;
Mais au lieu du chat, vous pouvez utiliser la grep inversée pour vous débarrasser des données indésirables, ce qui n'est pas pertinent pour cela. (ou le type de raffinement dont vous avez besoin).
À ce stade, vous ne travaillerez qu'avec de nombreux fichiers plus petits, et les commandes mentionnées ci-dessus fonctionneront mieux sur de nombreux fichiers plus petits.
Et lorsque vous avez terminé, vous pouvez utiliser une seconde boucle for pour reconstituer le nouveau fichier plus petit.
for f in `ls file_*`; do cat $f >> NewFile.data ; done;
Mise à jour Depuis que nous commençons à diviser les données en plusieurs fichiers, il va y avoir beaucoup de travail avec le disque dur et cela prend du temps. (Dans cette question apparemment 5min).
D'un autre côté, les prochaines étapes seraient probablement plus rapides.
Donc, cette méthode est probablement inutile pour une opération grep, awk, sed simple, mais si les modèles de recherche deviennent plus compliqués, ils pourraient devenir plus rapides.
perl -wlne '/^2011-02-24/ .. /^2011-02-25/ and print' log_file