Aller au contenu

suppression bloc lignes script shell


clive-guilde

Messages recommandés

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 ?!

Lien vers le commentaire
Partager sur d’autres sites

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

 

Modifié par pehache
Lien vers le commentaire
Partager sur d’autres 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

 

Lien vers le commentaire
Partager sur d’autres 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

 

Lien vers le commentaire
Partager sur d’autres sites

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.

Modifié par clive-guilde
Lien vers le commentaire
Partager sur d’autres 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

 

Lien vers le commentaire
Partager sur d’autres 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.

Lien vers le commentaire
Partager sur d’autres 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"

 

Lien vers le commentaire
Partager sur d’autres 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...

Lien vers le commentaire
Partager sur d’autres sites

@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"

 

 

Modifié par clive-guilde
Lien vers le commentaire
Partager sur d’autres 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.

 

Lien vers le commentaire
Partager sur d’autres sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Invité
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

Chargement
×
×
  • Créer...