Bienvenue visiteur (Inscription |  Connexion)
Qui est en ligne ?
Il y a : 21 utilisateurs en ligne, consultez le détail
Auteur Message
Guimauve2
#0 Message posté le : 01-02-2008 à 14:11:19


Naboo


Forum : Inscrit
Association :
Arrivé(e) le : 22-07-2003
Nombre de messages : 2128
Salut à tous,

Est-ce que l'un d'entre vous saurait comment capturer, dans un script Perl, l'output d'une commande comme wget (je veux juste le pourcentage de progression du téléchargement du fichier), où l'information change dynamiquement (la progression) sans qu'une nouvelle soit ajoutée dans la console ?

Ce serait spécifiquement pour la commande cdrecord ou wodim (pour graver des CDs).

Typiquement, il y a aurait une boucle dans mon script qui, à un intervalle de temps donné, irait lire ce pourcentage dans la sortie de la commande.

Le problème, après recherche sur Internet, est que la commande écrire sur /dev/tty (la console, directement) au lieu de stdout.

Je sais qu'en Python, c'est possible de le faire avec subprocess.Popen()... et fcntl, mais moi je veux le faire en Perl, vu que c'est un langage que je connais et apprécie beaucoup.

Perl permet d'ouvrir un pipe en tant que descripteur de fichier avec open, mais je n'ai réussi qu'à capture stdout, mais wget n'écrit pas sur stdout, mais à la console directement, donc je ne peux rien lire avec mon script Perl et la sortie de la commande est tout de même affiché sur la console (/dev/tty) même si capturée par Perl.

Cependant, je suis persuadé que c'est possible de contourner cela en Perl. Mais recherche sur Internet ont été jusqu'à présent infructueuse ; c'est pourquoi je me tourne vers vous pour trouver des pistes de solution.

Merci,

Guimauve2

-------------------------------------
GNU/Linux? Il y a moins bien, mais c'est plus cher!

Mon blog (pas très souvent updaté, mais tout de même...) : http://guimauve2.blogspot.com/
tamiel
#1 Message posté le : 01-02-2008 à 15:21:41


Hobbit


Forum : Inscrit
Association :
Arrivé(e) le : 17-10-2003
Nombre de messages : 1067
Un exemple (mais ca affiche les lignes à la suite, ca sera facile à corriger ...) :

open(OUT, "wget --progress=bar http://cdimage.debian.org/debian-cd/4.0_r2/i386/iso-cd/debian-40r2-i386-netinst.iso 2>&1 |");

while (<OUT>)

{

  if($_ =~ /%/)

  {

    print $_;

  }

}

close(OUT);



Pour wget en effet il dirige son affichage sur stderr au lieu de stdout (/dev/tty = stderr + stdout)

Le problème est que perl récupère uniquement stdout en utilisant <OUT> donc j'ai redirigé stderr de wget dans stdout .


Remarque : si le code est moche c'est normal ca fait quelques années que j'avais pas touché au perl ...

--Message édité par tamiel le 01-02-2008 à 15:22:08--


-------------------------------------
If you don't know, ask manpage !
Guimauve2
#2 Message posté le : 01-02-2008 à 19:45:25


Naboo


Forum : Inscrit
Association :
Arrivé(e) le : 22-07-2003
Nombre de messages : 2128
Le code est bon

Je pense que ça fonctionne. J'ai seulement pu tester avec une version Windows de wget et Perl, mais j'essaierai avec cdrecord (ou wodim) chez moi ce soir.

-------------------------------------
GNU/Linux? Il y a moins bien, mais c'est plus cher!

Mon blog (pas très souvent updaté, mais tout de même...) : http://guimauve2.blogspot.com/
Guimauve2
#3 Message posté le : 02-02-2008 à 18:21:29


Naboo


Forum : Inscrit
Association :
Arrivé(e) le : 22-07-2003
Nombre de messages : 2128
Avec wget ça fonctionne, mais avec cdrecord, pour la grauve des CDs, la progession est affichée dans la console (1 of 451 MB, 2 of 451 MB, etc.) mais seulement la dernière ligne (451 of 451 MB written) est capturée par Perl.

Est-ce que quelqu'un saurait pourquoi?

-------------------------------------
GNU/Linux? Il y a moins bien, mais c'est plus cher!

Mon blog (pas très souvent updaté, mais tout de même...) : http://guimauve2.blogspot.com/
Guimauve2
#4 Message posté le : 06-02-2008 à 14:14:43


Naboo


Forum : Inscrit
Association :
Arrivé(e) le : 22-07-2003
Nombre de messages : 2128
Update : en regardant du code existant du projet FreedomToaster, j'ai pu trouver une solution à mon problème :

1) Faire un fork()
2) Dans l'enfant, faire un appel ("system") à wodim (ou cdrecord) et rediriger STDOUT vers un fichier.
3) Supprimer le fichier lorsque la gravure est finie, et quitter.
4) Dans le parent, tant que le fichier de sortie existe (i.e. : n'a pas été supprimé par l'enfant), lire (system tail -1) la dernière ligne du fichier qui sera toujours (à partir d'un certain moment) la progression de la gravure. Il est à noter que la dernière ligne est toujours réécrire (je penche que c'est un \r à la fin de la ligne). Pour chaque ligne de progrès, faire un traitement approprié (ligne de progression, etc.).

--Message édité par Guimauve2 le 06-02-2008 à 14:19:02--


-------------------------------------
GNU/Linux? Il y a moins bien, mais c'est plus cher!

Mon blog (pas très souvent updaté, mais tout de même...) : http://guimauve2.blogspot.com/
Azollyx
#5 Message posté le : 06-02-2008 à 16:59:57


Naboo


Forum : Modérateur
Association : Président
Arrivé(e) le : 09-04-2006
Nombre de messages : 2085
Salut,
j'aurais deux remarques.

Tout d'abord, quitte à faire un fork, tu peux aussi faire un pipe : plutôt que d'écrire dans un fichier tu écris dans le pipe que tu lis depuis le père. Cela te fera économiser un fichier et des accès disques.
Ensuite, tu n'as absolument pas besoin de tail pour lire un fichier en Perl : tu peux simplement boucler sur le descripteur (que le pipe te fournira) :
while(<DESC>) {

      m!(\d\d %)!i;

      print $1.$/;

}

De manière générale, tu devrais toujours pouvoir te passer de la commande 'system', sauf dans certains cas précis (comme celui d'invoquer cdreacord même s'il faudrait vérifier la non-existance d'une lib/interface de cette ordre en Perl). Ce n'est pas portable comme approche.

Sinon, si tu veux jouer aux légos avec tes commandes, fait du Shell :
#!/bin/bash



invoke_cdreacord() {

      { ... } &>1

}



invoker_cdreacord... | while read line; do

      echo ${line##=} # pour commencer, je n'ai plus la sortie de cdreacord en tête

done


--Message édité par Azollyx le 06-02-2008 à 17:01:24--


-------------------------------------
toto
Guimauve2
#6 Message posté le : 06-02-2008 à 19:12:13


Naboo


Forum : Inscrit
Association :
Arrivé(e) le : 22-07-2003
Nombre de messages : 2128
Salut Azollyx,

En fait je me suis inspiré du projet FreedomToaster pour faire le programme, j'ai pas eu le temps de bien réfléchir à la question.

Cependant, j'avais déjà envisagé de faire un pipe. Le problème c'est que le progrès (0 of 600 MB written, 1 of 600 MB written, etc.) n'est pas "suivi" de manière dynamique par le pipe : le pipe va "bloquer" puis ne lire que la dernière ligne du progrès (600 of 600 MB written), ce qui n'est pas ce que je veux...

-------------------------------------
GNU/Linux? Il y a moins bien, mais c'est plus cher!

Mon blog (pas très souvent updaté, mais tout de même...) : http://guimauve2.blogspot.com/
Azollyx
#7 Message posté le : 06-02-2008 à 21:48:44


Naboo


Forum : Modérateur
Association : Président
Arrivé(e) le : 09-04-2006
Nombre de messages : 2085
ça ne serait pas plutôt que le pipe ne serait pas flushé ?

-------------------------------------
toto
Guimauve2
#8 Message posté le : 08-02-2008 à 02:10:52


Naboo


Forum : Inscrit
Association :
Arrivé(e) le : 22-07-2003
Nombre de messages : 2128
Flushé? Que veux-tu dire? Si c'est ça le problème, alors je prendrai cette solution haut la main!

-------------------------------------
GNU/Linux? Il y a moins bien, mais c'est plus cher!

Mon blog (pas très souvent updaté, mais tout de même...) : http://guimauve2.blogspot.com/
tamiel
#9 Message posté le : 08-02-2008 à 10:05:01


Hobbit


Forum : Inscrit
Association :
Arrivé(e) le : 17-10-2003
Nombre de messages : 1067
cdrecord n'a pas d'api utilisable et n'est pas libre.

-------------------------------------
If you don't know, ask manpage !
Azollyx
#10 Message posté le : 08-02-2008 à 10:18:14


Naboo


Forum : Modérateur
Association : Président
Arrivé(e) le : 09-04-2006
Nombre de messages : 2085
Guimauve2 >> En fait les sorties ne sont pas écrites en direct live : elles sont mises en tampon et envoyées sur la sortie (terminal, pipe...) que quand le tampon est plein ou flushé. En général, les sorties sont flushées automatiquement lorsqu'elle rencontre un '\n'. Il est probablement possible que le tampon soit flushé plus souvent quand tu écris dans un fichier que dans un pipe (car comme tu l'as dit, ce sont des '\r').
[...]
Essaye déjà, après avoir ouvert ton pipe, de modifier '$|' :
pipe(RDP,WRP);

if(fork()) {

    close(RDP);

    select RDP;

    $| = 1;

    cdrecord...

    close(WRP);

} else {

    close(WRP);

    while(RDP) {

        ...

    }

    close(RDP);

}


tamiel >> Je ne savais pas. Qu'en est-il de wodim/cdrkit ?

-------------------------------------
toto
tamiel
#11 Message posté le : 08-02-2008 à 11:28:49


Hobbit


Forum : Inscrit
Association :
Arrivé(e) le : 17-10-2003
Nombre de messages : 1067
http://lwn.net/Articles/198171/

-------------------------------------
If you don't know, ask manpage !
Azollyx
#12 Message posté le : 08-02-2008 à 19:48:38


Naboo


Forum : Modérateur
Association : Président
Arrivé(e) le : 09-04-2006
Nombre de messages : 2085


-------------------------------------
toto