OVH Cloud OVH Cloud

trap, diff, goto, awk... y en a pour tout le monde

7 réponses
Avatar
fredatwork
Bonjour,

j'essaie d'écrire un shell (ksh) comparant ligne à ligne 2 énormes fichiers,
j'utilise bdiff (comme diff mais pour les gros fichiers, bon choix ?)
quand les fichiers sont différents on souhaite lister les différences dans
un fichier mais
seulement les 5 premières (si il y en a un peu plus ce n'est pas trop grave)
mais on veut absolument éviter de produire un 3e énorme fichier, donc il
faut stopper
la comparaison et l'écriture du fichier.
Quand les fichiers sont identiques, on va jusqu'au bout.

J'ai donc pensé à lancer le bdiff en arrière plan,

bdiff fic1 fic2 > fic_sortie &

puis à le tuer quand il a écrit suffisamment de lignes dans le fichier de
sortie
ou attendre qu'il se termine si les fichiers en entrée sont identiques

Pour voir ou il en est dans l'écriture du fichier je fais un truc du genre :

taille_FIC_OUT=`ls -s fic_sortie | awk '{print $1}'`

Au passage, ca me fait mal de devoir sortir awk juste pour connaitre la
taille d'un fichier, ceci-dit
j'ai bien réfléchi et je ne vois pas de moyen plus simple, les ls | cut sont
exclus puisqu'il n'y a pas de formattage
en colonne de ls et que le format d'une ligne n'est pas fixe... si vous avez
d'autres idées je suis à l'écoute.

Ensuite, connaissant approximativement la taille d'une ligne issue du diff,
j'en déduis le nombre de lignes produites
par le diff, ce qui permet de majorer le nombre de différences produites

J'ai donc la boucle suivante :

while [ $nbligne -lt ${nb_max_lignes} ]
do
taille_FIC_OUT=`ls -s fic_sortie | awk '{print $1}'`
nbligne="taille_FIC_OUT/taille_ligne"
done

Je ne compte pas les lignes directement avec wc -l pour laisser l'accès au
fichier de sortie
uniquement au bdiff qui a déjà pas mal de boulot, qu'en pensez-vous ?

En meme temps, je dois surveiller que bdiff est toujours vivant, des fois
que les fichiers en entrée soient identiques...
Donc j'ai fait (ne vous moquez pas) :

TermineScript()
{
echo "bdiff est termine"
exit 0
}

LanceSleep()
{
echo "Lance Sleep"
`sleep ${TEMPS_ATTENTE}; kill -0 ${pid_diff} 2>/dev/null; if [ $? -ne 0 ];
then kill -USR1 $$; else kill -USR2 $$; fi` &
}

trap TermineScript USR1
trap LanceSleep USR2

et je lance une première fois la fonction LanceSleep en début de script
après le bdiff
Et là j'ai un problème, parce que de temps en temps j'ai un plantage à la
ligne :
taille_FIC_OUT=`ls -s fic_sortie | awk '{print $1}'`
L'erreur est " : is not an identifier"
Serait-ce mon trap qui casse mon pipe ?
Comment y remédier ?
Je ne vois pas de moyen d'éviter le pipe
Je ne connais pas de moyen d'empêcher le trap de se produire sur cette ligne
du code
Est-ce que le goto existe en ksh ? comment s'en sert-on ?
J'ai essayé (toujours interdit de rigoler) de faire un truc du genre :

LanceSleep()
{
echo "Lance Sleep"
`sleep ${TEMPS_ATTENTE}; kill -0 ${pid_diff} 2>/dev/null; if [ $? -ne 0 ];
then kill -USR1 $$; else kill -USR2 $$; fi` &
goto label
}

et

while [ $nbligne -lt ${nb_max_lignes} ]
do
label:
taille_FIC_OUT=`ls -s fic_sortie | awk '{print $1}'`
nbligne="taille_FIC_OUT/taille_ligne"
done

en espérant qu'à la fin du trap on recommence au début du while et que awk
n'essaie pas de lire le pipe cassé (meme si en fait je ne suis meme pas sur
que le
problème vienne du pipe) mais mon goto ne marche pas.

Que pensez-vous de l'approche générale ?

Bon, ca fait déjà pas mal de questions et je remercie
ceux qui ont lu tout ca jusqu'au bout.

Merci de vos réponses.

7 réponses

Avatar
Laurent Wacrenier
fredatwork écrit:
j'essaie d'écrire un shell (ksh) comparant ligne à ligne 2 énormes fichiers,
j'utilise bdiff (comme diff mais pour les gros fichiers, bon choix ?)


Sait pas. bdiff est non standart.

quand les fichiers sont différents on souhaite lister les différences dans
un fichier mais
seulement les 5 premières (si il y en a un peu plus ce n'est pas trop grave)
mais on veut absolument éviter de produire un 3e énorme fichier, donc il
faut stopper
la comparaison et l'écriture du fichier.
Quand les fichiers sont identiques, on va jusqu'au bout.

J'ai donc pensé à lancer le bdiff en arrière plan,

bdiff fic1 fic2 > fic_sortie &


Si seulles les 5 premières lignes sont interessantes,

bdiff fic1 fic2 | head -n 5 > fic_sortie

l'utilitaire devrait s'arreter quand il ne pourra plus écrire
(quand head sera terminé ayant lu 5 lignes)

Avatar
fredatwork
"Laurent Wacrenier" <lwa@ teaser . fr> a écrit dans le message news:

Si seulles les 5 premières lignes sont interessantes,

bdiff fic1 fic2 | head -n 5 > fic_sortie

l'utilitaire devrait s'arreter quand il ne pourra plus écrire
(quand head sera terminé ayant lu 5 lignes)


Effectivement, eh ben quand je vois tout ce que j'avais fait
alors que la solution tient en une ligne...
Merci bien.

Toutefois si quelqu'un a des réponses aux autres questions
incluses dans mon mail d'origine

Avatar
Stephane Chazelas
2004-09-21, 19:22(+02), fredatwork:
[...]
j'essaie d'écrire un shell (ksh) comparant ligne à ligne 2 énormes fichiers,


Tu essaies de reecrire ksh. Bonne idee, c'est vrai que
l'original etait pas super.

Peut-etre que tu veux plutot ecrire un script ?

[...]
taille_FIC_OUT=`ls -s fic_sortie | awk '{print $1}'`

Au passage, ca me fait mal de devoir sortir awk juste pour connaitre la
taille d'un fichier, ceci-dit
j'ai bien réfléchi et je ne vois pas de moyen plus simple, les ls | cut sont
exclus puisqu'il n'y a pas de formattage
en colonne de ls et que le format d'une ligne n'est pas fixe... si vous avez
d'autres idées je suis à l'écoute.


L'output dans ls -s n'est pas la taille du fichier mais son
occupation disque (comme dans du). C'est ls -l pour avoir la
taille.

t'as le "tr -s ' '" qui permet d'utiliser "cut -d' ' -f"

Sinon, tu as zsh, GNU stat, GNU find, perl... pour trouver la
taille d'un fichier.

T'as:

wc -c < fichier

(mais sur certains systemes, ca va lire "fichier" dans son
integralité).

Ensuite, connaissant approximativement la taille d'une ligne issue du diff,
j'en déduis le nombre de lignes produites


Tu as wc -l pour compter les lignes.

[...]
LanceSleep()
{
echo "Lance Sleep"
`sleep ${TEMPS_ATTENTE}; kill -0 ${pid_diff} 2>/dev/null; if [ $? -ne 0 ];


Que fait la ce « ` » ?

[...]
taille_FIC_OUT=`ls -s fic_sortie | awk '{print $1}'`
L'erreur est " : is not an identifier"
Serait-ce mon trap qui casse mon pipe ?


Je ne sais pas mais ceci est une erreur de ksh reportee par
exemple par read

$ ksh -c 'read ""'
ksh: : is not an identifier

Comment y remédier ?


Regarder la ou il peut y avoir une commande attandant le nom
d'une variable qui recoit un truc invalide.

[...]
Est-ce que le goto existe en ksh ? comment s'en sert-on ?


Non, pas de goto.

--
Stephane

Avatar
fredatwork
"Stephane Chazelas" a écrit dans le message
news:
2004-09-21, 19:22(+02), fredatwork:
[...]
j'essaie d'écrire un shell (ksh) comparant ligne à ligne 2 énormes
fichiers,



Tu essaies de reecrire ksh. Bonne idee, c'est vrai que
l'original etait pas super.

Peut-etre que tu veux plutot ecrire un script ?



Sans commentaire...

L'output dans ls -s n'est pas la taille du fichier mais son
occupation disque (comme dans du). C'est ls -l pour avoir la
taille.


Effectivement

t'as le "tr -s ' '" qui permet d'utiliser "cut -d' ' -f"

Sinon, tu as zsh, GNU stat, GNU find, perl... pour trouver la
taille d'un fichier.


Donc pas moyen d'éviter les | en ksh sauf avec wc -c

T'as:

wc -c < fichier

(mais sur certains systemes, ca va lire "fichier" dans son
integralité).


C'est apparemment le cas de mon système qui répond en plus d'une minute
sur un fichier de 800 Mo

LanceSleep()
{
echo "Lance Sleep"
`sleep ${TEMPS_ATTENTE}; kill -0 ${pid_diff} 2>/dev/null; if [ $? -ne
0 ];



Que fait la ce « ` » ?


La commande était sur deux lignes :

`sleep ${TEMPS_ATTENTE}; kill -0 ${pid_diff} 2>/dev/null; if [ $? -ne 0 ];
then kill -USR1 $$; else kill -USR2 $$; fi` &

Je lance tout ce bazar en arrière plan comme si c'était un SCRIPT shell
L'idée est de commencer par attendre un certain temps,
envoyer un signal à mon diff pour voir si il tourne toujours,
si il est mort j'envoie USR1 au programme principal ($$) qui se termine
alors
si il est toujours en vie j'envoie USR2 qui relance cette commande.

[...]
taille_FIC_OUT=`ls -s fic_sortie | awk '{print $1}'`
L'erreur est " : is not an identifier"
Serait-ce mon trap qui casse mon pipe ?


Je ne sais pas mais ceci est une erreur de ksh reportee par
exemple par read

$ ksh -c 'read ""'
ksh: : is not an identifier

Comment y remédier ?


Regarder la ou il peut y avoir une commande attandant le nom
d'une variable qui recoit un truc invalide.

eh bien je pense que le programme principal reçoit un signal pendant

l'instruction
taille_FIC_OUT=`ls -s fic_sortie | awk '{print $1}'`
plus précisément après le ls et avant le awk.
ça le déroute dans ma fonction LanceSleep, une fois que celle-ci est
terminée
il revient à l'instruction ci-dessus, et je pense que le awk essaie de lire
sur la sortie
standard mais qu'il n'y a plus rien à y lire parce que mon pipe est cassé

Ma question est : est-ce vraisemblable ?
Si oui comment éviter ça ?

[...]
Est-ce que le goto existe en ksh ? comment s'en sert-on ?


Non, pas de goto.



ok. ni aucune autre instruction équivalente j'imagine...

Merci beaucoup de ton aide.


Avatar
Stephane Chazelas
2004-09-22, 13:37(+02), fredatwork:
[...]
LanceSleep()
{
echo "Lance Sleep"
`sleep ${TEMPS_ATTENTE}; kill -0 ${pid_diff} 2>/dev/null; if [ $? -ne
0 ];



Que fait la ce « ` » ?


La commande était sur deux lignes :

`sleep ${TEMPS_ATTENTE}; kill -0 ${pid_diff} 2>/dev/null; if [ $? -ne 0 ];
then kill -USR1 $$; else kill -USR2 $$; fi` &


Je ne sais pas pourquoi tu veux eviter des pipes, mais note que
`...` cree un pipe (qui rammasse tout ce qu'ecrit le sous-shell
pour en faire des arguments de commandes).

Pour lancer un sous-shell, c'est des parentheses qu'il te faut:

(sleep ...) &

[...]
eh bien je pense que le programme principal reçoit un signal pendant
l'instruction
taille_FIC_OUT=`ls -s fic_sortie | awk '{print $1}'`
plus précisément après le ls et avant le awk.


Il n'y a pas de apres et avant. ls et awk sont lances en meme
temps. Si le shell recoit un USR1, ls et awk aussi et le shell
execute la trappe.

ça le déroute dans ma fonction LanceSleep, une fois que celle-ci est
terminée
il revient à l'instruction ci-dessus, et je pense que le awk essaie de lire
sur la sortie
standard mais qu'il n'y a plus rien à y lire parce que mon pipe est cassé

Ma question est : est-ce vraisemblable ?
Si oui comment éviter ça ?


Non, pas tres vraissemblable. Ce message d'erreur est un message
de ksh, il est probablement generé par les commandes dans la
trappe.

Mets un set -x au debut pour mieux voir ce qui se passe.

--
Stephane



Avatar
fredatwork
"Stephane Chazelas" a écrit dans le message
news:
Non, pas tres vraissemblable. Ce message d'erreur est un message
de ksh, il est probablement generé par les commandes dans la
trappe.

Mets un set -x au debut pour mieux voir ce qui se passe.



J'avais déjà fait la manoeuvre, mais peut-être sauras-tu interpréter
mieux que moi :

Je lance
ksh -x testdiff.ksh

ce qui donne (je te passe le début) :

Quelques centaines de fois :
+ [ 0 -lt 20 ]
+ + awk {print $1}
+ ls -s ficresult
taille_FIC_OUT=0
+ nbligne=taille_FIC_OUT/taille_ligne

puis finalement :
+ [ 0 -lt 20 ]
+ + awk {print $1}
+ ls -s ficresult
+ kill -0 18310
+ 2> /dev/null
+ [ 0 -ne 0 ]
+ kill -USR2 18309

+ LanceSleep
+ echo Lance Sleep
Lance Sleep
+ sleep 10
testdiff.ksh[57]: : is not an identifier

Fin du script

ligne 57 :
taille_FIC_OUT=`ls -s ${FIC_OUT} | awk '{print $1}'`

J'en étais arrivé à la conclusion citée précédemment,
quel est ton avis ?

A noter que le plantage ne survient pas forcément au premier signal USR2
envoyé :

$ testdiff.ksh
Lance Sleep
Lance Sleep
Lance Sleep

Lance Sleep
./testdiff.ksh[57]: : is not an identifier

J'ai bien noté la différence entre `...` et les parenthèses
J'ai effectué le remplacement.
Ca n'a pas résolu le problème ci-dessus mais je sais bien que tu ne
prétendais pas le contraire.
Quand aux pipes, je n'ai rien contre (pas de mauvais jeux de mots)
mais j'avais simplement l'impression que mon pipe était la source du
problème.
Des bonnes idées ?

Merci une nouvelle fois.

Avatar
Stephane Chazelas
2004-09-22, 16:10(+02), fredatwork:
[...]
taille_FIC_OUT=`ls -s ${FIC_OUT} | awk '{print $1}'`

J'en étais arrivé à la conclusion citée précédemment,
quel est ton avis ?

A noter que le plantage ne survient pas forcément au premier signal USR2
envoyé :

$ testdiff.ksh
Lance Sleep
Lance Sleep
Lance Sleep

Lance Sleep
./testdiff.ksh[57]: : is not an identifier
[...]


une explication possible:

tu as un

integer taille_FIC_OUT

et comme ls ou awk sont tues par un SIGUSR?, taille_FIC_OUT
contient un truc que ksh a du mal a considerer comme une
expression arithmetique.

C'est peut-etre un bug de ksh, ce ne serait pas le premier.

--
Stephane