Voilà, j'ai une petite ligne de shell script qui plante parfois, et je n'arrive pas à comprendre pourquoi:
cat /etc/fstab | fgrep -v $udi > /etc/fstab
Cette ligne est simplement supposée retirer toutes les lignes comprenant $udi (qui est toujours défini) du fichier fstab, $udi n'étant pas un motif complexe (une simple chaîne de caractères).
Parfois, et c'est hélas non reproduisible, je me retrouve avec un fstab totalement vide au lieu d'avoir juste le contenu du fichier fstab sans la ligne contenant $udi.
J'ai trouvé une solution de dépannage en passant par un fichier temporaire, puis un déplacement, mais j'aimerais bien comprendre ce qui cloche.
Merci.
# google et cat
Posté par NeoX . Évalué à 3.
le sujet a deja été abordé dans un autre forum et une recherche te donnerait des pistes.
entre autre ...
ta manip suppose que l'ouverture du fichier pour lecture se fasse entierement avant l'ouverture de ce meme fichier en ecriture.
la solution du fichier temporaire confirme cela,
ouverture du fichier en entrée -> lecture -> debut de traitement -> ouverture du fichier de sortie -> suite du traitement -> fin de lecture -> fin de traitement -> fin d'ecriture.
il y a des solutions comme les redirections multiples, les jonglages avec les options, et d'autres solutions que cat/grep
[^] # Re: google et cat
Posté par Grégory SCHMITT . Évalué à 2.
Bon, je viens de trouver une alternative avec sed (sed -i), je teste ça.
En revanche, pour les options, je suis perplexe, même après avoir regardé la Quick ref card de shell script.
[^] # Re: google et cat
Posté par Grégory SCHMITT . Évalué à 2.
sed -i "#$udi#d" /etc/fstab
Les '#' sont nécessaires car udi contient '/'.
Quand je pense que j'avais regardé sd pendant deux heures sans rien y trouver...
[^] # Re: google et cat
Posté par Grégory SCHMITT . Évalué à 2.
Merci de moinsser ce code !
[^] # Re: google et cat
Posté par NeoX . Évalué à 2.
-i pour qu'il fasse lui meme le fichier temporaire
-e pour executer le script sed qui suit
s#XXX#YYY#g pour remplacer tout les XXX par YYY partout dans le fichier
# warf
Posté par B. franck . Évalué à 4.
de l'autre une redirection qui écrase le contenu de ce même fichier...
L'ouverture de la redirection se faisant en premier, le contenu du fichier est avant tout écrasé.
[^] # Re: warf
Posté par Dan . Évalué à 3.
sed -i est une solution à ce problème comme dit plus haut, mais au final, on ne fait que le contourner et pour une autre commande ça ne marchera pas.
Personne n'a une vraie solution qui garderait la puissance du pipe ?
[^] # Re: warf
Posté par Hugues Hiegel (site web personnel) . Évalué à 4.
la seule vraie solution, c'est de passer par un fichier temporaire.
sache que quand tu utilises des pipes, toutes les commandes sont exécutées *en même temps*, et non pas l'une après l'autre...
donc en gros, la dernière commande va écrire dans le fichier pendant que la première le lit. Le comportement est indéterminé, et généralement se solde par un fichier vide (à cause justement du ">").
Pour l'utilisation d'un fichier temporaire, tu peux faire ça de façon plus ou moins "transparente" avec zsh :
fgrep -v "$udi" =(cat /etc/fstab) > /etc/fstab
le =(...) va demander à zsh de créer un fichier temporaire (typiquement sous /tmp/zshXXXXX) contenant le résultat de la commande entre parenthèses.
Et hop, plus de souci. :)
La solution la plus propre et la plus portable consiste à faire une lecture d'une copie du /etc/fstab, copie que tu peux créer dans ton /tmp (comme cela tu peux éventuellement ne pas te casser le chou à supprimer le fichier).
[^] # Re: warf
Posté par Grégory SCHMITT . Évalué à 1.
[^] # Re: warf
Posté par Hugues Hiegel (site web personnel) . Évalué à 2.
[^] # Re: warf
Posté par Grégory SCHMITT . Évalué à 2.
Bon, j'ai trouvé un bon remplacement avec sed -i.
Comme $udi contient des '/', je crée une nouvelle variable $udi_sed qui échappe tous les slashs, car malheureusement, il semble impossible d'utiliser un autre caractère de délimitation avec l'extension d (du genre #...#d).
udi_sed=$(echo $udi | sed "s#/#\\\/#g")
Et ensuite, un coup de sed:
sed -i "/$udi_sed/d" /etc/fstab
Pour info, udi vient de HAL (unique device identifier); il faudra que je regarde du côté des règles de nommage d'udi pour vérifier qu'il ne peut pas inclure '*', ',' ou tout autre caractère faisant partie des expressions régulières / rationnelles...
[^] # Re: warf
Posté par benoar . Évalué à 3.
"d" se met à la fin du pattern à matcher, donc on ne peut pas savoir à l'avance quels sont tes délimiteurs, contrairement à "s//" qui est au début.
[^] # Re: warf
Posté par bob6 . Évalué à 3.
sed -i "\#$udi#d" /etc/fstab
En revanche sed interprète ce qu'il y a entre // (ou entre \##) comme une expression régulière, tu ferais mieux d'échapper quand même les '.', '*' et compagnie... Je peux aussi te proposer:echo "`fgrep -v $udi /etc/fstab`" > /etc/fstab
Comme ça t'es sûr que fstab sera fermé en lecture avant d'être ouvert en écriture.Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.