web-dev-qa-db-fra.com

Supprimer plusieurs lignes du fichier lorsque du texte est trouvé

J'ai vu plusieurs réponses supprimer une seule ligne avec sed ou grep, mais j'ai besoin de rechercher une ligne, de supprimer celle-ci et les 2 lignes précédentes. Par exemple, dans le fichier ~/.profile, j'ai des lignes comme celles-ci:

#Set environment variable
export NAME=value
# (blank line here)

Je voudrais donc rechercher #Set environment variable, et le supprimer, puis supprimer la ligne suivante export NAME=variable (le contenu ne devrait pas avoir d'importance), ainsi que la ligne vierge suivante. Les noms de variable export sont dynamiques, mais le commentaire sera toujours le même. Il pourrait y avoir d’autres variables export sans le commentaire ci-dessus, que je ne souhaite pas supprimer.

Comment puis-je accomplir cela?

4
Chris G

Avec la nouvelle version de GNU sed (fournie avec Ubuntu), vous pouvez reproduire les nouvelles lignes littéralement:

sed -z 's/#Set environment variable\nexport [^\n]\+\n\n//g' file.txt
  • L'option -z traitera les lignes des fichiers d'entrée comme étant terminées par ASCII NUL plutôt que par une nouvelle ligne. Nous pouvons donc utiliser \n pour faire correspondre les nouvelles lignes.

  • #Set environment variable\n correspondra à la première ligne (avec la nouvelle ligne)

  • export [^\n]\+\n correspondra à la deuxième ligne commençant par export

  • Comme la troisième ligne est vide, simplement \n fera

  • Ensuite, nous remplaçons tout le motif associé au blanc pour conserver la portion désirée.

Dans vous voulez écraser le fichier avec le contenu modifié:

sed -zi.bak 's/#Set environment variable\nexport [^\n]\+\n\n//g' file.txt

Le fichier original sera conservé sous le nom file.txt.bak, si vous ne voulez pas utiliser simplement sed -zi.

Voici un test:

$ cat file.txt 
#Set environment variable
export NAME=value
#some text

#Set environment variable
export NAME=value

check
value

export some=value

#Set environment variable
export NAME=value

foo bar



$ sed -z 's/#Set environment variable\nexport [^\n]\+\n\n//g' file.txt 
#Set environment variable
export NAME=value
#some text

check
value

export some=value

foo bar
4
heemayl

Il est très facile de faire cela avec la commande delete standard de sed:

cp ~/.profile ~/.profile.bak
sed '/#Set environment variable/,+2 d' <~/.profile.bak >~/.profile

Soyez prudent avec votre ~/.profile

2
ludvik02

Bien que votre question donne l’impression que vous cherchez un moyen de le faire en ligne de commande, si j’étais dans votre situation et que je ne voulais le faire que pour un ou deux fichiers, j’utiliserais emacs.

emacs a la capacité d'apprendre une séquence de frappes au clavier, puis de les répéter autant de fois que vous le souhaitez. Donc, dans votre cas, je voudrais ouvrir ~/.profile dans emacs et puis tapez

C-x ( C-s #Set environment variable C-a C-k C-k C-k C-x )

[qui, en mots, fait ceci: Cx (signifie "commence à apprendre cela"; Cs signifie "recherche de", alors nous recherchons la variable d'environnement #Set, puis Ca signifie "retour au début de la ligne, et le trois Ck signifie "supprimer cette ligne", et enfin Cx) signifie "arrêtez d'apprendre cela".]

Après avoir tapé ces commandes une fois, emacs a supprimé trois lignes, mais il a également appris à le faire par cœur. Vous pouvez donc taper

C-x e

et il le fera encore, ou

C-u 100 C-x e

et il le fera 100 fois (ou s’arrêtera quand il ne trouvera plus de lignes avec "# variable d’environnement" dans).

L'avantage d'utiliser emacs est que vous pouvez voir vos modifications se faire "en direct", et pour une personne paranoïaque comme moi qui a peur qu'un seul type de frappe puisse supprimer beaucoup de choses que je ne voulais pas effacer, cela me rend beaucoup plus heureux [ Dès que les choses tournent mal dans emacs, vous pouvez simplement revenir en arrière et les corriger avec C-_].

0
Yannick