J'ai le code suivant qui supprimera les lignes avec le motif banana
et 2 lignes après:
sed '/banana/I,+2 d' file
Jusqu'ici tout va bien! Mais j'en ai besoin pour supprimer 2 lignes avant banana
, mais je ne peux pas l'obtenir avec un «signe moins» ou autre (similaire à ce qui grep -v -B2 banana file
devrait faire mais ne le fait pas):
teresaejunior@localhost ~ > LC_ALL=C sed '-2,/banana/I d' file
sed: invalid option -- '2'
teresaejunior@localhost ~ > LC_ALL=C sed '/banana/I,-2 d' file
sed: -e expression #1, char 16: unexpected `,'
teresaejunior@localhost ~ > LC_ALL=C sed '/banana/I,2- d' file
sed: -e expression #1, char 17: unknown command: `-'
shell-script
text-processing
sed
awk
Teresa e Junior
la source
la source
awk '{l[m=NR]=$0}/banana/{for(i=NR-2;i<=NR;i++)delete l[i]}END{for(i=1;i<=m;i++)if(i in l)print l[i]}'
. Ce n'est pas efficace, donc ce n'est qu'un indice, pas une solution.tac file | sed ... | tac
. : Psed '/banana/,+2d' file
cela fonctionnera égalementawk 'tolower($0)~/bandana/{print prev[!idx];print prev[idx]} {idx=!idx;prev[idx]=$0}' filein
comme il s'agit d'un commentaire et non d'une réponse (il existe déjà d'autres réponses), je n'entrerai pas dans trop de détails, mais le point crucial est que vous avez toujours le deux précédents enregistrements prev [0] et prev [1], la « plus fraîche » en fonction de l'itération , mais toujoursprev[idx]
, donc quand vous imprimez, vous imprimez en!idx
puisidx
commande. Quoi qu'il en soit, alternezidx
et mettez le record en coursprev[idx]
.Réponses:
Sed ne revient pas en arrière: une fois la ligne traitée, c'est fait. Donc, «trouver une ligne et imprimer les N lignes précédentes» ne fonctionnera pas tel quel, contrairement à «trouver une ligne et imprimer les N lignes suivantes» qui est facile à greffer.
Si le fichier n'est pas trop long, puisque vous semblez être d'accord avec les extensions GNU, vous pouvez utiliser
tac
pour inverser les lignes du fichier.Un autre angle d'attaque consiste à maintenir une fenêtre coulissante dans un outil comme awk. Adaptation à partir de Y a-t-il une alternative aux commutateurs -A -B -C de grep (pour imprimer quelques lignes avant et après)? (avertissement: peu testé):
Usage:
/path/to/script -v pattern='banana' -v before=2
la source
sed
peut également faire des fenêtres coulissantes, mais le script résultant est généralement si illisible qu'il est plus facile à utiliserawk
.awk
script n'est pas tout à fait correct; en l'état, il imprime les lignes vides et manque les dernières lignes. Cela semble le corriger, mais ce n'est peut-être pas l'idéal ou le droit lui-même:if (NR-before in h) { print...; delete...; }
... et dans laEND
section:for (i in h) print h[i]
... De plus, le script awk imprime la ligne correspondante, mais pas latac/sec
version; mais la question est un peu ambiguë à ce sujet .. Le script awk "original", auquel vous avez fourni un lien, fonctionne bien .. Je l'aime bien ... Je ne sais pas comment le "mod" ci-dessus affecte l' impression après lignes ...C'est assez facile avec ex ou vim -e
L'expression se lit comme suit: pour chaque ligne contenant de la banane dans la plage allant de la ligne actuelle -2 à la ligne actuelle, supprimez.
Ce qui est cool, c'est que la plage peut également contenir des recherches en arrière et en avant, par exemple, cela supprimera toutes les sections du fichier commençant par une ligne contenant apple et se terminant par une ligne contenant orange et contenant une ligne avec banane:
la source
Utilisation de la "fenêtre coulissante" dans
perl
:la source
Vous pouvez le faire assez simplement avec
sed
:Je ne sais pas pourquoi quelqu'un dirait le contraire, mais pour trouver une ligne et imprimer les lignes précédentes
sed
incorpore laP
primitive\n
rint intégrée qui n'écrit que jusqu'au premier caractère ewline dans l'espace modèle. LaD
primitive elete complémentaire supprime ce même segment d'espace de motif avant de recycler récursivement le script avec ce qui reste. Et pour l'arrondir, il existe une primitive pour ajouter laN
ligne d'entrée ext à l'espace de motif après un\n
caractère ewline inséré .Pour qu'une seule ligne
sed
soit tout ce dont vous avez besoin. Vous remplacez simplementmatch
par votre expression rationnelle et vous êtes en or. Cela devrait également être une solution très rapide .Notez également qu'il comptera correctement un
match
précédent immédiatementmatch
comme déclencheur de sortie silencieuse pour les deux lignes précédentes et calmera également son impression:Pour que cela fonctionne pour un nombre arbitraire de lignes, tout ce que vous avez à faire est d'obtenir une piste.
Alors:
... supprime les 5 lignes précédant toute correspondance.
la source
En utilisant
man 1 ed
:la source