J'ai besoin de rechercher plusieurs fichiers journaux (tous les fichiers générés au cours des dernières 24 heures, tous conservés dans le même répertoire) pour trouver la dernière occurrence d'une chaîne. Voici la commande que j'ai écrite:
find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1
Mais cela ne renvoie que la dernière ligne pour un fichier. Des suggestions sur la façon de modifier cela pour obtenir toutes les lignes?
bash
shell-script
text-processing
grep
Lokesh
la source
la source
Réponses:
En supposant que les installations GNU:
la source
find
exécuter des commandes sur des fichiers en utilisant-exec
. Avecbash -c
, nous générons unbash
shell qui parcourt les fichiers trouvés parfind
et s'exécutetac .. | grep -m1 fileprefix
sur chacun-d" "
avec coupe. Citations doubles au lieu de simplesfind
commande peut filtrer le préfixe du fichier; celagrep
ne devrait pas être nécessaire pour cela. Il est également surprenant que la chaîne de recherche ne figure pas dans cette réponse.Si tout est dans un seul répertoire, vous pouvez faire:
S'il s'agit de fichiers volumineux, il peut être utile d'accélérer les choses en utilisant
tac
pour imprimer le fichier dans l'ordre inverse (dernière ligne en premier), puisgrep -m1
pour faire correspondre la première occurrence. De cette façon, vous évitez d'avoir à lire l'intégralité du fichier:Ces deux supposent qu'il n'y a aucun répertoire correspondant
fileprefix
. S'il y en a, vous obtiendrez une erreur que vous pouvez simplement ignorer. Si c'est un problème, recherchez uniquement les fichiers:Si vous avez également besoin du nom de fichier imprimé, ajoutez
-H
à chaquegrep
appel. Ou, si votregrep
ne le prend pas en charge, dites-lui de rechercher également/dev/null
. Cela ne changera pas la sortie maisgrep
étant donné que plusieurs fichiers sont fournis, il affichera toujours le nom du fichier pour chaque hit:la source
tac
non plus. Il sortira dès que la première correspondance sera trouvée. Je viens de tester avec un fichier texte 832M et un motif trouvé sur la dernière ligne.grep -m 1 pattern file
outil ~ 7 secondes et atac file | grep -m1 pattern
pris0.009
.... fonctionnera si vous avez GNU
sed
qui prend en charge l'-s
option de fichiers séparés et un POSIXfind
.Vous devriez probablement ajouter les qualificatifs
! -type d
or-type f
, cependant, car essayer de lire un répertoire ne sera pas très utile, et restreindre davantage la plage aux fichiers normaux pourrait éviter une lecture suspendue à un fichier de canal ou de périphérique série.La logique est incroyablement simple -
sed
écrase sonh
ancien espace avec une copie de toute ligne d'entrée qui correspondsearchstring
, puisd
supprime de la sortie toutes les lignes d'entrée, mais la dernière pour chaque fichier d'entrée. Quand il arrive à la dernière ligne, ilx
modifie ses espaces d'attente et de motif, et donc s'il asearchstring
été trouvé pendant qu'il lisait le fichier, la dernière occurrence de ce type sera imprimée automatiquement en sortie, sinon il écrit une ligne vierge. (ajouter/./!d
à la fin dused
script si cela n'est pas souhaitable) .Cela fera une seule
sed
invocation par quelques 65k fichiers d'entrée - ou quelle que soit votreARG_MAX
limite. Cela devrait être une solution très performante, et est tout simplement implémentée.Si vous voulez également les noms de fichiers, étant donné un GNU récent,
sed
vous pouvez les écrire sur des lignes séparées avec laF
commande, ou bien vous pouvez les faire imprimerfind
dans une liste distincte par lot en ajoutant le-print
primaire après+
.la source
Que diriez-vous:
Ce qui précède vous donne une belle sortie avec la dernière occurrence d'une chaîne de recherche dans chaque fichier suivi du nom du fichier respectif après la virgule (modifiez la partie ", $ 1" sous echo pour changer la mise en forme ou supprimez-la si inutile). Un exemple de sortie qui recherche la chaîne de recherche «10» dans les fichiers avec un préfixe de nom de «fichier» est le suivant:
la source
Celui - ci utilise GNU
grep
de-H
et-n
options pour toujours imprimer à la fois le nom et le numéro de ligne de tous les matches, il trie par nom de fichier et linenumber, et les tuyaux dans awk, qui stocke le dernier match pour chaque nom de fichier dans un tableau, et éventuellement des impressions il.Une méthode assez brutale, mais ça marche.
la source