J'ai un fichier journal trace.log
. J'y ai besoin de grep pour le contenu contenu dans les chaînes <tag>
et </tag>
. Il existe plusieurs ensembles de cette paire de chaînes et il me suffit de renvoyer le contenu entre le dernier ensemble (en d'autres termes, à partir de la variable tail
du fichier journal).
Crédit supplémentaire: Est-ce que je peux retourner le contenu contenu dans les deux chaînes uniquement si le contenu contient "testString"?
Merci d'avoir regardé.
EDIT: Les paramètres de recherche et sont contenus sur différentes lignes avec environ 100 lignes de contenu les séparant. Le contenu est ce que je suis après ...
Utilisez tac
pour imprimer le fichier en sens inverse, puis grep -m1
pour n’imprimer qu’un seul résultat. Le regard en arrière et en avant vérifie le texte entre <tag>
et </tag>
.
tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)'
Compte tenu de ce fichier
$ cat a
<tag> and </tag>
aaa <tag> and <b> other things </tag>
adsaad <tag>and last one</tag>
$ tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)'
and last one
EDIT: Les paramètres de recherche et sont contenus sur différentes lignes avec environ 100 lignes de contenu les séparant. Le contenu est ce que je suis après...
Alors c'est un peu plus compliqué:
tac file | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]};
/<tag>/ {p=0; split($0, a, "<tag>"); $0=a[2]; print; exit};
p' | tac
L'idée est d'inverser le fichier et d'utiliser un indicateur p
pour vérifier si le <tag>
est déjà apparu ou non. L'impression commencera lorsque </tag>
apparaîtra et se terminera lorsque <tag>
arrivera (parce que nous lisons dans l'autre sens).
split($0, a, "</tag>"); $0=a[1];
récupère les données avant </tag>
split($0, a, "<tag>" ); $0=a[2];
récupère les données après <tag>
Étant donné un fichier a
comme ceci:
<tag> and </tag>
aaa <tag> and <b> other thing
come here
and here </tag>
some text<tag>tag is starting here
blabla
and ends here</tag>
La sortie sera:
$ tac a | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]}; /<tag>/ {p=0; split($0, a, "<tag>"); $0=a[2]; print; exit}; p' | tac
tag is starting here
blabla
and ends here
Si comme moi, vous n'avez pas accès à tac car votre administrateur système ne jouera pas au ballon, vous pouvez essayer:
grep pattern file | tail -1
Une autre solution que grep serait séduite:
tac file | sed -n '0,/<tag>\(.*\)<\/tag>/s//\1/p'
tac file
imprime le fichier dans l'ordre inverse (cat
en arrière), puis sed
passe de la ligne de saisie 0
à la première occurrence de <tag>.*<\tag>
et substitue <tag>.*<\tag>
par la seule partie se trouvant dans <tag>
. L'indicateur p
imprime la sortie, qui a été supprimée par -n
.
Edit: Cela ne fonctionne pas si <tag>
et </tag>
sont sur des lignes différentes. Nous pouvons toujours utiliser sed
pour cela:
tac file | sed -n '/<\/tag>/,$p; /<tag>/q' | sed 's/.*<tag>//; s/<\/tag>.*//' | tac
De nouveau, nous utilisons tac
pour lire le fichier à l'envers, puis la première commande sed
lit à partir de la première occurrence de et se ferme quand elle le trouve. Seules les lignes entre les deux sont imprimées. Ensuite, nous passons le processus à un autre processus sed
pour le dépouiller et finalement inverser les lignes avec tac
.
Perl -e '$/=undef; $f=<>; Push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1]' ex.txt
Crédit supplémentaire: De toute façon, je peux retourner le contenu contenu dans le deux chaînes uniquement si le contenu contient "testString"?
Perl -e '$/=undef; $f=<>; Push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1] if ($a[-1]~=/teststring/);' ex.txt
Un peu non testé awk qui gère plusieurs lignes:
awk '
BEGIN {retain="false"}
/<\tag>/ {retain = retain + $0; keep="false"; next}
/<tag>/ {keep = "true"; retain = $0; next}
keep == "true" {retain = retain + $0}
END {print retain}
' filename
Nous commençons juste à lire le fichier; lorsque nous atteignons la, nous commençons à garder des lignes. Quand on frappe le, on s'arrête. Si nous en touchons un autre, nous effaçons la chaîne conservée et recommençons. Si vous voulez toutes les chaînes, imprimez à chaque