Jump to content
clive-guilde

suppression bloc lignes script shell

Recommended Posts

Bonjour aux codeurs,

 

Voilà je souhaiterais pouvoir utiliser un script shell me permettant de supprimer systématiquement un bloc de ligne dans des fichiers systèmes (il y en a plus de 250). Voici le bloc de ligne en question :

	AutoXferHostInfo {
		autoXferHostName = "AWS"
		autoXferMode = 1
	}

Il faut savoir que chaque ligne peut apparaitre à un autre endroit dans le fichier. Il faut donc que le script ne supprime ces caractères que si et seulement si ces 3 lignes sont successives dans le fichier système 🤔.

Autre point, on ne peut pas s'appuyer sur le numéro des lignes car il est variable en fonction des fichiers systèmes 😡.

J'étais parti sur des commandes de type sed, genre :

sed -i '' 's/texte_original/texte_de_remplacement/g' mon_nom_de_fichier

et laisser texte_de_remplacement en champ vide pour supprimer le texte_original. Seulement le problème c'est que je n'arrive pas à inclure les retours chariot dans le champs texte_original.

 

D'où ma question, comment inclure les retour chariot dans les blocs de texte à recherche ?

Merci pour votre expertise les informaticiens 😉!

Share this post


Link to post
Share on other sites
Posted (edited)

Le petit exercice du soir 🙂 ...

Avec un script bash, à mettre dans un fichier toto.bash, à appeler ainsi :
toto.bash < in.txt > out.txt

J'ai fait comme s'il y avait 1 tabulation en tête des lignes 1 et 4, et 2 tabulations en tête des lignes 2 et 3...

EDIT : tabulations codées avec la séquence $'\t' pour ne pas risquer la confusion avec des espaces

#!/bin/bash

line1=$'\t''AutoXferHostInfo {'
line2=$'\t'$'\t''autoXferHostName = "AWS"'
line3=$'\t'$'\t''autoXferMode = 1'
line4=$'\t''}'

block=0
while IFS= read line ; do
	if   [ $block -eq 0 -a "$line" = "$line1" ] ; then
		block=1
	elif [ $block -eq 1 -a "$line" = "$line2" ] ; then
		block=2
	elif [ $block -eq 2 -a "$line" = "$line3" ] ; then
		block=3
	elif [ $block -eq 3 -a "$line" = "$line4" ] ; then
		block=0
	else
		[ $block -gt 0 ] && echo "$line1"
		[ $block -gt 1 ] && echo "$line2"
		[ $block -gt 2 ] && echo "$line3"
		if [ "$line" == "$line1" ] ; then
			block=1
		else
			echo "${line}"
			block=0
		fi
	fi
done

 

Edited by pehache

Share this post


Link to post
Share on other sites

Le premier test de la boucle est redondant en fait...

#!/bin/bash

line1=$'\t''AutoXferHostInfo {'
line2=$'\t'$'\t''autoXferHostName = "AWS"'
line3=$'\t'$'\t''autoXferMode = 1'
line4=$'\t''}'

block=0
while IFS= read line ; do
	if [ $block -eq 1 -a "$line" = "$line2" ] ; then
		block=2
	elif [ $block -eq 2 -a "$line" = "$line3" ] ; then
		block=3
	elif [ $block -eq 3 -a "$line" = "$line4" ] ; then
		block=0
	else
		[ $block -gt 0 ] && echo "$line1"
		[ $block -gt 1 ] && echo "$line2"
		[ $block -gt 2 ] && echo "$line3"
		if [ "$line" == "$line1" ] ; then
			block=1
		else
			echo "${line}"
			block=0
		fi
	fi
done

 

Share this post


Link to post
Share on other sites

Et une version plus facilement adaptable à des blocs plus longs si besoin :

#!/bin/bash

linesref=($'\t''AutoXferHostInfo {' \
          $'\t'$'\t''autoXferHostName = "AWS"' \
          $'\t'$'\t''autoXferMode = 1' \
          $'\t''}' \
         )

n=${#linesref[*]}

declare -a lines

i=0
while IFS= read lines[$i] ; do
	let i++
	if [ $i -eq $n ] ; then
		block=true
		for (( j=0; j < $n; j++ )); do
			[ "${lines[$j]}" != "${linesref[$j]}" ] && block=false
		done
		if [ $block == true ] ; then
			let i=0
		else
			echo "${lines[0]}"
			for (( j=1; j < $n; j++ )); do
				let k=$j-1
				lines[$k]=${lines[$j]}
			done
			let i--
		fi
	fi
done
for (( j=0; j < $i; j++ )) ; do
	echo "${lines[$j]}"
done

 

Share this post


Link to post
Share on other sites
Posted (edited)

Bonjour @pehache,

 

Merci pour le retour, je viens de tester mais j'ai seulement le dernier } qui est effacé (c'est à dire juste la dernière ligne de in.txt) dans le out.txt alors que je souhaiterai que tout le bloc soit effacé. Il doit y avoir une erreur quelque part mais où ????

 

Au passage ce ne sont pas des tabulations mais des espaces dans le fichier. Il y a 4 espaces pour la ligne 1 et 4 et 6 espaces pour les lignes 2 et 3.

Edited by clive-guilde

Share this post


Link to post
Share on other sites

Tu as essayé quelle version ? Enfin, normalement j'ai testé les deux et ça fonctionnait. Tu as bien remplacé les tabulations par des espaces dans le script ?

Après fais gaffe aux copiés-collés depuis le forum : il y a des caractères spéciaux invisibles qui traînent, je ne sais pas d'où ils viennent... Une fois que tu as créé le script recopie les 4 chaînes de caractères depuis un de tes fichiers, ce sera plus sûr.

in.txt :

AAAAAAAAAAAAA
BBBBBBBBBBBBB
    AutoXferHostInfo {
      autoXferHostName = "AWS"
    }
    AutoXferHostInfo {
      autoXferHostName = "AWS"
      autoXferMode = 1
    }
AAAAAAAAAAAAA
      autoXferMode = 1
CCCCCCCCCCCCC
 Z

out.txt :

AAAAAAAAAAAAA
BBBBBBBBBBBBB
    AutoXferHostInfo {
      autoXferHostName = "AWS"
    }
AAAAAAAAAAAAA
      autoXferMode = 1
CCCCCCCCCCCCC
 Z

 

Share this post


Link to post
Share on other sites

ok super @pehache ça marche merci beaucoup pour ton aide surement une erreur de copier-coller.

Dernière petite question de noob en code, comment intégrer ton script au mien sachant que le mien a cette forme :

#!/bin/bash

for file in toto_*.txt
do
echo "Process on $file ..."

LC_ALL=C sed -i '' 's/"ADW7"/"AWS"/g' $file

done
echo "processing of abdomen.proto files finished"

C'est à dire comment intégrer ton <in.txt> à mes différents fichiers d'entrée toto_1.txt, toto_2.txt, ... tout en sachant que je ne souhaite pas que toto_1.txt, toto_2.txt change de nom seulement qu'ils soient tous modifiés par mes commandes et du coup la tienne également.

 

Désolé de te poser cette question c'est surement une question de débutant mais je ne suis pas informaticien donc pas très à l'aise en shell.

Share this post


Link to post
Share on other sites

Le plus simple est d'appeler mon script depuis le tien. Et il faut un fichier intermédiaire à chaque fois :

#!/bin/bash

for file in toto_*.txt
do
	echo "Process on $file ..."

	LC_ALL=C sed -i '' 's/"ADW7"/"AWS"/g' $file

	4lines.bash < $file > tmpfile.txt   # "4lines.bash" étant mon script
	mv tmpfile.txt $file

done
echo "processing of abdomen.proto files finished"

 

Share this post


Link to post
Share on other sites

Les shell scripts unix ça permet de faire plein de choses mais c'est assez cryptique, et surtout la cohérence/consistance des syntaxes est assez, euh, olé olé... On peut faire plus ou moins les mêmes choses par des moyens différents, il y a des empilements de syntaxes avec des logiques différentes (la raison est historique, des éléments plus modernes ont été ajoutés mais en gardant la compatibilité avec les anciens scripts), etc...

Share this post


Link to post
Share on other sites
Posted (edited)

@pehache

Super merci beaucoup. Au passage il manquait un sh pour faire appel à ton scrip du coup le code devient

#!/bin/bash

for file in toto_*.txt
do
	echo "Process on $file ..."

	LC_ALL=C sed -i '' 's/"ADW7"/"AWS"/g' $file

	sh 4lines.bash < $file > tmpfile.txt   # "4lines.bash" étant mon script
	mv tmpfile.txt $file

done
echo "processing of abdomen.proto files finished"

 

 

Edited by clive-guilde

Share this post


Link to post
Share on other sites

Ah ? Ca devrait marcher sans le "sh" normalement (si le script appelé a bien les permissions d'exécution, ce qui semblait être le cas dans le message que tu as modifié). Sans doute que sur Mac le dossier courant n'est pas dans les chemins de recherche des exécutables ("echo $PATH" pour vérifier), et dans ce cas "./4lines.bash" marcherait.

Au passage mieux vaut mettre "bash 4lines.bash", même si en pratique sur la plupart des machines actuelles /bin/sh est un lien vers /bin/bash.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×