web-dev-qa-db-fra.com

Supprimer toutes les lignes du milieu d'une ligne correspondant à une chaîne jusqu'à ce que la deuxième correspondance soit trouvée

J'essaie de supprimer les messages d'erreur imprimés dans mon fichier. J'ai ceci:

 addr:1122c:1234:
 addr:11230:5678:
 addr:11223:01Error:abcdef(x, y) = z, value = a
Error:hijklm(v, q) = w, value = b
Error:nopqrst(x, y) = z, value = d
Error:uvwxyz(l, m) = z, value = e
Error:1234(u, t) = z, value = f
Error:567(r, s) = z, value = g
err_total = 9846, err_sub = 0, err_mask = 239
1 Duration: xyz, abc
0 Duration: pqr, def
23:
 addr:11238:4567:
 addr:1123c:8901:

J'ai besoin de supprimer tous les messages d'erreur jusqu'à la prochaine adresse apparaît. La sortie requise est:

 addr:1122c:1234:
 addr:11230:5678:
 addr:11223:0123:
 addr:11238:4567:
 addr:1123c:8901:

J'ai essayé:

sed -i "/\bError\b/d" file_name

Mais cela supprime les lignes commençant par Erreur et ne supprime pas la ligne où la chaîne d'erreur a commencé au milieu.

Je suis nouveau dans les expressions régulières, une explication serait vraiment utile.

Edit: J'utilise sed -i '/Error/,/addr/d' filename mais cela supprime toute la ligne et ne donne pas ce que je recherche.

3
lost_wanderer

sed n'est pas vraiment bon dans la correspondance multiligne.
Vous pouvez le tromper pour faire ce que vous voulez, mais alors imo Perl est plus facile à gérer.

Essaye ça:

Perl -pe 'BEGIN{undef $/;}; s/Error.*?(^[0-9]* Duration: [^\n]*\n)+//smg;'

Explication:

  • BEGIN { do_something; }: Faire quelque chose une fois au début
  • undef $/: Ignorer les fins de ligne
  • s/// Remplaçant
  • Error.* Correspond à n'importe quelle chaîne commençant par "Erreur".
  • ? Rendre la correspondance précédente ungreedy, car elle s'arrête à la correspondance suivante ou, dans ce cas, au groupe correspondant ...
  • ()+ Créez un groupe correspondant, qui doit être mis en correspondance au moins une fois (+).
  • ^[0-9]* Duration: [^\n]*\n: Fait correspondre la ligne entière avec Duration, y compris.

( via )

4
pLumo

Plutôt que de supprimer les lignes "Error:", pourquoi ne pas extraire uniquement les lignes souhaitées avec:

grep -E '^ addr:' file_name | sed -e 's/Error:.*//'
2
waltinator

Cela générera le résultat recherché:

$ cat file_name | grep -v \
    -e '^Error:' \
    -e '^err_total' \
    -e '^.*[0-9] Duration:' | \
    sed ':a;$!N;s/Error:.*\n\(.*[0-9]\):/\1:/;ta;P;D'

Frist supprime tous les éléments Error, err_total et 12345 Duration:. Recherchez ensuite le Error: ... interrompant votre sortie, supprimez la nouvelle ligne (\n), recherchez la prochaine occurrence d’un nombre (.*[0-9]:) et ajoutez-la à la ligne en cours.

1
Simon Sudler