Léa-Linux & amis :   LinuxFR   GCU-Squad   GNU
Comment éviter la création d'un fichier temporaire
Envoyé par: Sve@r

Bonjour à tous
Vous avez sûrement déjà eu à faire en shell un truc qui modifie un fichier. Le problème, c'est qu'on ne peut pas écrire
cat fichier |truc_qui_modifie >fichier
Car le système commence par vider le fichier en question. On utilise alors un fichier intermédiaire dit "de travail" et on part dans ce genre d'algo :
cat fichier |truc_qui_modifie >travail
mv travail fichier
rm -f travail

Le gros problème de ce genre d'algo, c'est qu'il ne faut pas oublier qu'on bosse en environnement multitâches/multiutilisateurs donc il faut éviter, si 2 utilisateurs lancent le même script, que les scripts interfèrent l'un l'autre en travaillant dans le même fichier.
L'utilisateur avisé utilisera alors judicieusement les variables "$HOME" et "$$" pour travailler en local avec des fichiers au nom unique dans ce genre :
cat fichier |truc_qui_modifie >$HOME/tmp/travail.$$
mv $HOME/tmp/travail.$$ fichier
rm -f $HOME/tmp/travail.$$

Comme le nom de fichier est utilisé 3 fois, il faut faire 3 modif si on veut le changer. La solution suivante consiste à mettre ce nom de fichier dans une variable
fic_travail="$HOME/tmp/travail.$$"
cat fichier |truc_qui_modifie >$fic_travail
mv $fic_travail fichier
rm -f $fic_travail

C'est satisfaisant tant au point de vue "efficacité" que "protection contre les accès concurrents". Le problème c'est qu'il y a création d'un fichier sur disque et que c'est lent.

Pour ma part, j'ai tenté plein de solution pour éviter à tout prix cette écriture disque en cherchant dans l'environnement pipe comment faire pour travailler en mémoire.
J'ai même tenté sans succès le truc tordu suivant :
mknod fifo p
cat fichier |truc_qui_modifie >fifo &
cat fifo >fichier

Puis j'ai trouvé une piste intéressante à base de "tee" dans la solution suivante :
cat fichier |truc_qui_modifie |tee fichier 1>/dev/null

Ca, ça a semblé marcher parfaitement jusqu'au moment où j'ai voulu inclure cet algo dans un autre pipe comme le "flux |while read lig" permettant de traiter le flux ligne par ligne
Exemple
generer_une_liste_de_fichier |while read fic
do
....# traitement de chaque fichier
....cat $fic |truc_qui_modifie |tee $fic 1>/dev/null
done

Et là, c'est la cata. De façon aléatoire, certains fichiers sont traités, d'autres sont vidés. Et si on recommence l'algo, les fichiers traités ne sont pas les mêmes ni les fichiers vidés que lors du lancement précédent.
Je pense que les pipe imbriqués posent de sérieux problèmes. Si quelqu'un a des commentaires à faire...

L'homme qui murmurait à l'oreille des pingouins
[fr.lang.free.fr]

Poste le Thursday 30 November 2006 20:05:29
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire

Et avec ed (et peut-être lockfile-touch ou lockfile ou équivalent)?

----

Basile STARYNKEVITCH

Membre de l'APRIL « promouvoir et défendre le logiciel libre » - adhérez vous aussi à l'APRIL!

Projet logiciel libre: RefPerSys

Poste le Thursday 30 November 2006 21:59:18
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: oudoubah

Si tu peux estimer quelle est la taille de tes fichiers lors du traitement, tu peux créer un ramdisk et y déposer tes fichiers temporaires.

Concernant les tubes imbriqués, il y aurait peut être une solution (tordue) en jouant avec les descripteurs de fichiers, ainsi les stdout seront bien séparés.

Une autre solution (moins belle) serait de créer un certain nombre de tubes nommés, et de rediriger chaque commande dans un tel tube :-/

Tu as lu les docs. Tu es devenu un informaticien. Que tu le veuilles
ou non. Lire la doc, c'est le Premier et Unique Commandement de
l'informaticien.
-+- TP in: Guide du Linuxien pervers - "L'évangile selon St Thomas"

Poste le Friday 1 December 2006 13:57:49
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: Sve@r

Citation
oudoubah
Si tu peux estimer quelle est la taille de tes
fichiers lors du traitement, tu peux créer un ramdisk et y déposer tes fichiers temporaires.
En fait, la notion de "fichier temporaire" implique de penser au nettoyage final et la gestion des accès concurrents. Que ce soit sur un vrai disque ou un ramdisk ne change rien (pour celui qui veut programmer "propre")

Citation
oudoubah
Concernant les tubes imbriqués, il y aurait peut
être une solution (tordue) en jouant avec les
descripteurs de fichiers, ainsi les stdout seront
bien séparés.
J'ai essayé aussi ce genre de manip comme l'exemple suivant:
exec 3 >fichier_a_modifier
cat fichier_a_modifier |modif 1>&3
Idem => Le fichier "fichier_a_modifier" est écrasé

Citation
oudoubah
Une autre solution (moins belle) serait de créer
un certain nombre de tubes nommés, et de rediriger
chaque commande dans un tel tube
Déjà tenté (cf premier post) ici
mknod fifo p
cat fichier |truc_qui_modifie >fifo &
cat fifo >fichier
Le fichier "fichier" est écrasé...

Pas évident ce genre de recherche profonde en shell...


L'homme qui murmurait à l'oreille des pingouins
[fr.lang.free.fr]

Poste le Thursday 7 December 2006 22:57:50
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: Mushroom

Salut,

En fait, le problème doit être que l'ouverture en écriture efface le fichier avant qu'il soit lu. C'est pour ça que :

cat test1 | cat >test1; cat test1
Ne donne jamais rien... l'aléatoire de tee s'expliquerait alors par ce qu'il fait en premier : s'il commence par ouvrir le fichier en écriture, rien ne s'affiche; s'il l'ouvre d'abord en lecture, le fichier est lu, fermé, pui réouvert en écriture et tout ce passe bien... Les deux opérations doivent être lancées simultanément, étant donné que c'est le but de la commande, d'où l'aléatoire...


Perso, je ferais comme ça :

Mise en place de l'environnement de test :
echo -e "\n1 toto\n\n#EOF" >test1
echo -e "\n2 titi\n\n#EOF" >test2
echo -e "\n3 tutu\n\n#EOF" >test3
echo -e "\n4 tata\n\n#EOF" >test4
echo -e "\n5 tete\n\n#EOF" >test5

Traitement :
ls test* | while read fichier; do echo "$(cat $fichier | sed s/t/p/g )" > $fichier;done

Là tu es sûr que chaque fichier est bien fermé avant d'être réouvert en écriture...

Poste le Saturday 16 December 2006 13:47:07
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: Sve@r

Citation
Mushroom
En fait, le problème doit être que l'ouverture en
écriture efface le fichier avant qu'il soit lu.
C'était aussi mon idée. Dès que le shell interprète une redirection il commence par eraser le fichier...

Citation
Mushroom
Perso, je ferais comme ça :
echo "$(cat "fichier_a_modifier" |truc_qui_modifie)" > fichier_a_modifier

ASTUCIEUX... mais si le shell commence par faire sa redirection il commencera quand-même par eraser le fichier... Pourtant j'ai l'impression que t'as testé ton truc et que ça marche... donc le shell ne doit pas commencer par la redirection... donc je vois pas trop.
Cependant j'apprécie l'idée du sous-processus - Je tenterai ça dès que possible
Merci

L'homme qui murmurait à l'oreille des pingouins
[fr.lang.free.fr]

Poste le Saturday 16 December 2006 15:59:58
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: Mushroom

Re.

Citation
Sve@r
ASTUCIEUX... mais si le shell commence par faire sa redirection il commencera quand-même par eraser le fichier...
J'ai testé plusieurs fois, ça marche très bien... mais tu as raison ça infirme l'explication... En fait, je ne comprends rien J'ai essayé ça :

#!/bin/sh

# Initialisation du test.
echo -e "\n1 toto\n\n#EOF" >test1
echo -e "\n2 titi\n\n#EOF" >test2
echo -e "\n3 tutu\n\n#EOF" >test3
echo -e "\n4 tata\n\n#EOF" >test4
echo -e "\n5 tete\n\n#EOF" >test5

ls -1 test* | while read fichier; do
    (
    # fichier en entrée standard
    exec 0<$fichier 
    cat | sed s/t/p/g > $fichier
    )
done
cat  test*

Et j'obtiens la même instabilité au résultat qu'avec tee : avec bash, avec ash en 2.6.x comme en 2.4.x...

De plus, si on reprend la solution donnée en modifiant la place du tuyau :

echo "$(cat "fichier_a_modifier") | truc_qui_modifie > fichier_a_modifier
On se heurte à nouveau à un vidage de la cible... c'est comme si le tuyau refusait de lâcher totalement son entrée avant d'avoir atteint la fin. Si on veut vraiment un truc manipulable, il faudra sans doute passer par une variable :

#!/bin/sh

# Initialisation du test.
echo -e "\n1 toto\n\n#EOF" >test1
echo -e "\n2 titi\n\n#EOF" >test2
echo -e "\n3 tutu\n\n#EOF" >test3
echo -e "\n4 tata\n\n#EOF" >test4
echo -e "\n5 tete\n\n#EOF" >test5

ls -1 test* | while read fichier; do
   output="$(cat $fichier)"
   echo "$output" | sed s/t/p/g >$fichier
done
cat test*

Remarque, c'est en RAM et c'est propre une fois le script terminé. ;-)

Poste le Saturday 16 December 2006 22:34:11
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: Sve@r

Citation
Mushroom
c'est comme si le tuyau refusait de lâcher totalement son entrée avant d'avoir atteint la fin.
Hypothèse à retenir.

J'aime bien ce genre d'expérience "poussée" en shell...

Citation
Mushroom
Si on veut vraiment un truc manipulable, il faudra sans doute passer
par une variable :

#!/bin/sh
output="$(cat fichier_a_modifier |truc_qui_modifie)"
echo "$output" >fichier_a_modifier

Remarque, c'est en RAM et c'est propre une fois le script terminé.
Finallement t'as raison. Peut-être qu'il faut effectivement arrêter de se torturer le neurone et rester sur cette approche simplissime du pb. C'est dommage que Brugmans n'ait pas été tenté d'apporter sa contribution à ce topic. Il a des idées souvent top...

L'homme qui murmurait à l'oreille des pingouins
[fr.lang.free.fr]

Poste le Sunday 17 December 2006 13:08:23
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: Mushroom

<myway.linus>Brugmans est un lâche, tout juste bon à proposer des solutions idiotes pour hamsters dégénérés débutant en shell (je précise pour les crétins que je ne mets pas de "s" à "débutant" parce que c'est ici un participe présent, présent sans "a" ).</fuckthestandards>

Poste le Sunday 17 December 2006 19:47:27
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: Mushroom

Hello,

Autrement, tu peux jeter un oeil sur la commande flock pour les question de non-concurrence. Je l'ai découverte il n'y a pas longtemps. ;-)

Poste le Friday 29 December 2006 20:17:12
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: Sve@r

Citation
Mushroom
Hello,

Autrement, tu peux jeter un oeil sur la commande
flock pour les question de non-concurrence. Je
l'ai découverte il n'y a pas longtemps.
Tiens ? C'est vraiment marrant - Je l'ai découverte aussi mi-décembre (je connaissais déjà la fonction C mais pas la commande)...


L'homme qui murmurait à l'oreille des pingouins
[fr.lang.free.fr]

Poste le Saturday 30 December 2006 14:39:27
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: oudoubah

Il y a une solution qui passe par un descripteur de fichier, et la suppression du fichier

#!/bin/sh

exec 3< $1
rm $1
cut -d':' -f 1 <&3 | tr '[a-z]' '[A-Z]' i| head -n 1> $1

Un exemple :

Citation

[oudoubah@Tuxtop tmp]$ !cp
cp /etc/passwd ./
[oudoubah@Tuxtop tmp]$ ./toto.sh passwd
[oudoubah@Tuxtop tmp]$ cat passwd
ROOT
[oudoubah@Tuxtop tmp]$

On utilise ici le fait qu'un fichier n'est supprimé que lorsque tous les processus qui l'utilisent l'ont fermé, et qu'on peut donc y accéder via le descripteur correspondant au fichier du processus correspondant.
Un exemple :
Citation

[oudoubah@Tuxtop tmp]$ cat toto.sh
#!/bin/sh

exec 3< $1
rm $1
sleep 120
[oudoubah@Tuxtop tmp]$ ./toto.sh passwd &
[1] 2762
[oudoubah@Tuxtop tmp]$ ls -l /proc/2762/fd/
total 0
lrwx------ 1 oudoubah users 64 jan 30 19:32 0 -> /dev/pts/0
lrwx------ 1 oudoubah users 64 jan 30 19:32 1 -> /dev/pts/0
lrwx------ 1 oudoubah users 64 jan 30 19:32 2 -> /dev/pts/0
lr-x------ 1 oudoubah users 64 jan 30 19:32 255 -> /tmp/toto.sh*
lr-x------ 1 oudoubah users 64 jan 30 19:32 3 -> /tmp/passwd (deleted)
[oudoubah@Tuxtop tmp]$ cp /proc/2762/fd/3 passwd2
[oudoubah@Tuxtop tmp]$ ls
enlightenment-oudoubah/ gconfd-oudoubah/ orbit-oudoubah/ passwd2 toto.sh*

Je m'abstient du cat passwd2 pour vérifier que la copie est correcte ;-)

Tu as lu les docs. Tu es devenu un informaticien. Que tu le veuilles
ou non. Lire la doc, c'est le Premier et Unique Commandement de
l'informaticien.
-+- TP in: Guide du Linuxien pervers - "L'évangile selon St Thomas"

Poste le Tuesday 30 January 2007 19:37:47
Répondre     Citer    
Re: Comment éviter la création d'un fichier temporaire
Envoyé par: Sve@r

Citation
oudoubah
Il y a une solution qui passe par un descripteur
de fichier, et la suppression du fichier

#!/bin/sh

exec 3< $1
rm $1
cut -d':' -f 1 <&3 | tr '' '' i| head -n
1> $1

Un exemple :

$ !cp
cp /etc/passwd ./
$ ./toto.sh passwd
$ cat passwd
ROOT
$

On utilise ici le fait qu'un fichier n'est
supprimé que lorsque tous les processus qui
l'utilisent l'ont fermé, et qu'on peut donc y
accéder via le descripteur correspondant au
fichier du processus correspondant.
Astucieux :-)


L'homme qui murmurait à l'oreille des pingouins
[fr.lang.free.fr]

Poste le Wednesday 31 January 2007 21:49:40
Répondre     Citer    
Serveur sous Linux
Envoyé par: NewNell

Bonjours a tous .. je suis en plein révision pour mon exam de linux ...:,( et c pas gagné /?-(
j'ai récupérer l'exam de l'an dernier pour réviser un peu .. et j'ai besoin d'aide ///

voila le déu d'exam ///

A/ Pour le serveur maitre et les autres serveurs

Aprés formatage de la disquette il faut créer es répertoir suivant dedant

/control (Dans lequel vous redirigerez les redémarrage du réseau et des serveurs dans les fichiers suivants:

°restartnet (/etc/init.d/network restart>>/mnt/floppy/control/restartnet
°route(route>>/mnt/floppy/control/restartnet)
°hostname(route>>/mnt/floppy/control.hostname)
°namedrestart (même chose que précedemment)
°nfsrestart(même chose que précedemment)

/observatios (pour laisser des observations particuliere)
/etc
/etc( avec tous les sous répertoires qui permettent la configuration du réseau sur votre système d'exploitation)
/var
/var/named


B/¨Pour le serveur esclave
/slave
/slave/etc
/slave/etc (avec tous les sous répertoires qui permettent la configuration du réseau sur votre serveur esclave)

/slave/var
/slave/var/named

je sais créer les répertoir .. je vx un aide pour les commande (route, hostname, namedrestart, nfsrestart)

et aussi je vous savoir c'est quoi les sous répertoires dans les 2 parties A et B

Merci D'avance :ange::-)

Poste le Tuesday 6 February 2007 13:45:40
Répondre     Citer    

Veuillez vous authentifier auparavant pour commenter.

 

Ce forum !
Comment éviter la création d'un fichier temporaire
Pour poser vos questions sur les scripts shell, le Perl, le C, etc... Attention : nous ne sommes pas des spécialistes du dev, ce forum est juste pour de petites aides ponctuelles concernant le développement et les outils de développement.

Sauf mention contraire, les documentations publiées sont sous licence Creative-Commons