[gull] Script rechercher-remplacer

Claude Paroz paroz at email.ch
Fri Jun 17 21:18:01 CEST 2005


Le vendredi 17 juin 2005 à 09:12 +0200, Daniel Cordey a écrit :
> On Thursday 16 June 2005 23:11, Claude Paroz wrote:
> 
> >     # loop for every line of the file
> >     while [ `wc -l $f | cut -d" " -f1` -ge $i ]
> 
> Maintenant que j'y regarde de plus pret... petits commentaires :
> 
> - J'ecrirais plutot :
> 
> 	while read line
> 	do
> 		...
> 	done <$f

Intéressant, mais ça n'a pas l'air de marcher. Peut-être un conflit
entre les deux read ??

> - Une ecriture :
> 
> 	'wc  -l $f | cut -d" " -f1`
> 
> Peut-etre remplacee par :
> 
> 	$(wc -l <$f)
> 
> Remplacer les `` par $() n'a plus l'avantage de performance qu'il avait il y a 
> longtemps mais c'est plus lisible (moins de chance de ne pas voir la 
> difference entre `et '). Autrement, le fait d'utiliser '<' evite de se 
> retrouver avec le nom du fichire que l'on elimine avec le 'cut'

Merci, j'en prends note.


> >                 # replace term and place newline in variable
> >                 newline=`printf "$newline\n" | sed -n
> > 's/'$1'/'$PATTERN'/1p'`
> 
> - Pas besoin de preciser '-n', ni de '1p'. Un simple 'sed "s/$1/${PATTERN}/"

Effectivement, c'était un reste d'autres tests...

> Je prefere aussi utiliser les "" dans le cas ou je veux pouvoir 'evaluer' des 
> variables a l'interieur. Cela evite les multiples ouvertures/fermetures de 
> chaine de carcateres avec les ''. Aussi, j'ai pris l'habitude d'encapsuler 
> les variable entre {}, afin de limiter les risques d'erreurs en delimitant 
> clairement le nom d'une variable. Par exemple :
> 
> X='toto'
> XX='titi'
> 
> a="$XX"
> 
> N'est peut-etre pas forcement ce que l'on veut, mais :
> 
> a="${X}X"
> b="${XX}"
> 
> n'est plus ambigu
> 
> >         # write the line in the new file
> >         printf "$newline\n" >> $f.tmp
> >         i=`expr $i + 1`
> 
> 
> printf est couteux ! (en temps...). Un simple 
> 
> 	echo "${newline" >> ${f}.tmp
> 
> Aurait suffit. 

Mon problème, c'est qu'avec echo, je perdais mes tabulateurs en début de
ligne, et fini l'indentation :-( C'est probablement par ce que j'avais
oublié de mettre la variable entre "". Maintenant, ça marche avec echo.

> Mais... le plus couteux dans l'affaire est le '>>'. En effet, 
> comme cette commande se trouve dans uen boucle, le shell doit, a chaque 
> boucle, ouvrir le fichier, deplacer le curseur a la fin puis refermer le 
> fichier. Il est mieux d'encapsuler toute la boucle (exterieur !) dans :
> 
> 	{
> 		for ...
> 		do
> 			...
> 			echo "${newline}"
> 		done
> 	} > ${f}.tmp

Le problème, c'est qu'il y a d'autres "echo" dans la boucle dont le
résultat ne doit pas aboutir dans le fichier, mais seulement à l'écran.

> 
> >     mv $f.tmp $f
> 
> Peut-etre serait-il judicieux de prendre l'habitude de tester si le fichier 
> creer est non vide; ca peut-etre le signe d'un bug (le fait qu'il soit vide). 
> Donc :
> 
> 	test -s ${f}.tmp && mv ${f}.tmp ${f}

Effectivement, c'est une bonne idée.

Merci pour ces conseils. Je remets une nouvelle version, avec encore un
autre bug corrigé (remplacement du nième terme). Je n'ai pas
systématiquement ajouté les {} :

PATTERN="\<indexterm\>\<primary\>&\<\/primary\>\<\/indexterm\>"
FILESTOSCAN="en/*.xml"

for f in $(grep -il $1 $FILESTOSCAN)
do
	echo "Find/Replace in file $f"
	touch $f.tmp
	i=1
	# loop for every line of the file
	while [ $(wc -l <$f) -ge $i ]
	do
		# read a line in the file
		line=$(sed -n "${i}s/.*/&/p" $f)
		newline=$line
		j=1
		while [ -n "$(echo $line | grep $1)" ]
		do
			echo -e "\n-------------------------------------------------\nLine
$i :"
			echo $line | grep --colour=auto $1
			echo -e "\nDo you want to index the first term '$1' in this line ?
[y-n]"
			read answer
			if  [ "${answer}" == "y" ]
			  then 
				# replace term and place newline in variable
				newline=$(echo "${newline}" | sed "s/$1/${PATTERN}/$j")
			fi
			# replace term with xxx in the line for catching second occurrence in
next loop
			line=$(echo $line | sed "s/$1/xxx/")
			j=$(expr $j + 1)
		done
		# write the line in the new file
		echo "${newline}" >> $f.tmp
		i=$(expr $i + 1)
	done
	# write new file over original one, if new file non empty
	test -s $f.tmp && mv $f.tmp $f
done

Claude

Claude




More information about the gull mailing list