1
votes

sed - supprimer de pattern1 avant pattern2 à pattern3 après pattern2

J'essaie de supprimer les lignes entre deux motifs, y compris les lignes avec les motifs eux-mêmes, si un autre motif est trouvé entre eux, mais je ne sais pas comment y remédier. et que vous souhaitez supprimer les lignes 6 à 11 car le motif autre que celui-ci se trouve entre les motifs start et end :

/^start$/{$!{N;/^start\n(.*\n)*notthis.*\n(.*\n)*end/d;ty;P;D;:y}}

J'ai changé ce que je pensais comprendre de cette réponse en quelque chose comme ceci, mais cela ne fonctionne pas:

start
AHBUe3Ar5NoD
3EcuCcD2QCja
7VmlKFbD8Rbi
end
start
OgytsRhZbD8T
notthis
0PlcUh2RLvVW
tsz2S80SyW9p
end
start
dQ5qiZCvBqcK
SufdS40X1Sh2
B1cyNshOj2Z4
end

Est-ce parce que N ajoute seulement la ligne suivant le modèle initial ^ start $ à l'espace de motif et ignore ce qui suit? Et quelle serait la bonne façon de réaliser ce que j'essaye de faire?


1 commentaires

Espérons qu'il arrive un moment lors de l'écriture d'un script rempli de runes comme /^start$/{$!{N;/^start\n(.*\n)*notthis.*\n(.*\n) * end / d; ty; P; ‌ D;: y}} quand vous pensez à vous-même - "qu'est-ce que je fais ???"!


3 Réponses :


3
votes

sed est pour des substitutions simples sur des chaînes individuelles, c'est tout . Pour toute autre chose, vous devriez utiliser awk, par exemple avec GNU awk pour mult-char RS ce bref script produira la sortie que vous voulez à partir de l'entrée que vous avez postée:

$ cat tst.awk
/start/ { f = 1 }
f {
    rec = rec $0 ORS
    if ( /end/ ) {
        if ( rec !~ /notthis/ ) {
            printf "%s", rec
        }
        rec = ""
        f = 0
    }
}
$
$ awk -f tst.awk file
start
AHBUe3Ar5NoD
3EcuCcD2QCja
7VmlKFbD8Rbi
end
start
dQ5qiZCvBqcK
SufdS40X1Sh2
B1cyNshOj2Z4
end

ou plus claire, plus robuste et plus facile à améliorer avec n'importe quel awk: p>

$ awk 'BEGIN{RS=ORS="end\n"} !/notthis/' file
start
AHBUe3Ar5NoD
3EcuCcD2QCja
7VmlKFbD8Rbi
end
start
dQ5qiZCvBqcK
SufdS40X1Sh2
B1cyNshOj2Z4
end

Ce qui précède fonctionnera de manière efficace et robuste en utilisant n'importe quel awk dans n'importe quel shell sur chaque boîte UNIX, est facile à comprendre et facile à modifier si / quand vos exigences changent.


2 commentaires

Merci, fonctionne comme un charme. Pourriez-vous expliquer les deux?


Le premier lit un enregistrement entier (bloc de texte multiligne) à la fois où chaque enregistrement se termine par end \ n et imprime l'enregistrement s'il ne contient pas notthis . Le second définit un indicateur lorsque start est trouvé, construit l'enregistrement une ligne à la fois pendant que cet indicateur est défini, puis lorsque end est trouvé, imprime l'enregistrement si il ne contient pas rien de tel . Faites-moi savoir si vous avez des questions spécifiques sur la syntaxe après avoir jeté un coup d'œil à la page de manuel awk.



0
votes

Voici un autre script awk . J'espère correspondre à la description partielle du problème.

script.awk

start
AHBUe3Ar5NoD
3EcuCcD2QCja
7VmlKFbD8Rbi
end
start
OgytsRhZbD8T
0PlcUh2RLvVW
tsz2S80SyW9p
end
notthis
start
dQ5qiZCvBqcK
SufdS40X1Sh2
B1cyNshOj2Z4
end
notthis

input.txt

XXX

en cours d'exécution:

awk -f script.awk input.txt

sortie:

start
AHBUe3Ar5NoD
3EcuCcD2QCja
7VmlKFbD8Rbi
end
start
OgytsRhZbD8T
notthis
0PlcUh2RLvVW
tsz2S80SyW9p
end
notthis
start
dQ5qiZCvBqcK
SufdS40X1Sh2
B1cyNshOj2Z4
notthis
end
notthis


1 commentaires

Assurez-vous de comprendre la discussion sur stackoverflow.com/q/23934486/1745001 si vous envisagez d'utiliser une expression de plage .



0
votes

Cela pourrait fonctionner pour vous (GNU sed):

sed '/^start/{:a;N;/end$/!ba;/notthis/d}' file

Rassemblez les lignes entre start et end et si elles contiennent la chaîne notthis les supprimer.


0 commentaires