contexte :
os : windows xp
perl : activeperl 5.8.2
Depuis un programme perl, je veux exécuter un autre programme du même
répertoire, et récupérer ses sorties. Pour cela, j'utilise la commande
open avec un "fichier" sous la forme "programme options |". Voici mon
[couic]
'C:/Program' n'est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.
Quelqu'un peut-t'il expliquer pourquoi ça plante, et surtout proposer
une solution qui marche !
contexte :
os : windows xp
perl : activeperl 5.8.2
Depuis un programme perl, je veux exécuter un autre programme du même
répertoire, et récupérer ses sorties. Pour cela, j'utilise la commande
open avec un "fichier" sous la forme "programme options |". Voici mon
[couic]
'C:/Program' n'est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.
Quelqu'un peut-t'il expliquer pourquoi ça plante, et surtout proposer
une solution qui marche !
contexte :
os : windows xp
perl : activeperl 5.8.2
Depuis un programme perl, je veux exécuter un autre programme du même
répertoire, et récupérer ses sorties. Pour cela, j'utilise la commande
open avec un "fichier" sous la forme "programme options |". Voici mon
[couic]
'C:/Program' n'est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.
Quelqu'un peut-t'il expliquer pourquoi ça plante, et surtout proposer
une solution qui marche !
Dans l'article <eu7pms$cui$,
a dit...contexte :
os : windows xp
perl : activeperl 5.8.2
Depuis un programme perl, je veux exécuter un autre programme du même
répertoire, et récupérer ses sorties. Pour cela, j'utilise la commande
open avec un "fichier" sous la forme "programme options |". Voici mon
[couic]'C:/Program' n'est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.
Quelqu'un peut-t'il expliquer pourquoi ça plante, et surtout proposer
une solution qui marche !
Le problème provient de l'espace dans votre nom de chemin.
Si dans une console vous tapez
C:/Program Files/tmp/essai2.pl arg1 arg2
vous aurez le message d'erreur 'C:/Program' n'est pas reconnu en tant que
commande interne ou externe...etc car l'espace sert aussi à séparer les
arguments. La ligne est interprétée avec la commande C:/Program et les
trois arguments : Files/tmp/essai2.pl, arg1, arg2
Pour lever l'ambiguité il faut utiliser des guillemets :
"C:/Program Files/tmp/essai2.pl" arg1 arg2
Dans votre script, il suffit de rajouter des guillemets autour de $cmd
if (open (my $fh, ""$cmd" $option |") ) {
Dans l'article <eu7pms$cui$1@sxcom1.cnrm.meteo.fr>,
eric_nospam_gerbier@meteo.fr.invalid a dit...
contexte :
os : windows xp
perl : activeperl 5.8.2
Depuis un programme perl, je veux exécuter un autre programme du même
répertoire, et récupérer ses sorties. Pour cela, j'utilise la commande
open avec un "fichier" sous la forme "programme options |". Voici mon
[couic]
'C:/Program' n'est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.
Quelqu'un peut-t'il expliquer pourquoi ça plante, et surtout proposer
une solution qui marche !
Le problème provient de l'espace dans votre nom de chemin.
Si dans une console vous tapez
C:/Program Files/tmp/essai2.pl arg1 arg2
vous aurez le message d'erreur 'C:/Program' n'est pas reconnu en tant que
commande interne ou externe...etc car l'espace sert aussi à séparer les
arguments. La ligne est interprétée avec la commande C:/Program et les
trois arguments : Files/tmp/essai2.pl, arg1, arg2
Pour lever l'ambiguité il faut utiliser des guillemets :
"C:/Program Files/tmp/essai2.pl" arg1 arg2
Dans votre script, il suffit de rajouter des guillemets autour de $cmd
if (open (my $fh, ""$cmd" $option |") ) {
Dans l'article <eu7pms$cui$,
a dit...contexte :
os : windows xp
perl : activeperl 5.8.2
Depuis un programme perl, je veux exécuter un autre programme du même
répertoire, et récupérer ses sorties. Pour cela, j'utilise la commande
open avec un "fichier" sous la forme "programme options |". Voici mon
[couic]'C:/Program' n'est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.
Quelqu'un peut-t'il expliquer pourquoi ça plante, et surtout proposer
une solution qui marche !
Le problème provient de l'espace dans votre nom de chemin.
Si dans une console vous tapez
C:/Program Files/tmp/essai2.pl arg1 arg2
vous aurez le message d'erreur 'C:/Program' n'est pas reconnu en tant que
commande interne ou externe...etc car l'espace sert aussi à séparer les
arguments. La ligne est interprétée avec la commande C:/Program et les
trois arguments : Files/tmp/essai2.pl, arg1, arg2
Pour lever l'ambiguité il faut utiliser des guillemets :
"C:/Program Files/tmp/essai2.pl" arg1 arg2
Dans votre script, il suffit de rajouter des guillemets autour de $cmd
if (open (my $fh, ""$cmd" $option |") ) {
ce que je ne comprends pas, c'est pourquoi sans arguments, il
n'interprete pas "C:/Program" comme une commande et
"Files/tmp/essai2.pl" comme un argument ? une bizarreté de
l'interpreteur de commande ?
merci, ça marche !
(j'en étais presque à recoder tout ça avec IPC::Open3 )
ce que je ne comprends pas, c'est pourquoi sans arguments, il
n'interprete pas "C:/Program" comme une commande et
"Files/tmp/essai2.pl" comme un argument ? une bizarreté de
l'interpreteur de commande ?
merci, ça marche !
(j'en étais presque à recoder tout ça avec IPC::Open3 )
ce que je ne comprends pas, c'est pourquoi sans arguments, il
n'interprete pas "C:/Program" comme une commande et
"Files/tmp/essai2.pl" comme un argument ? une bizarreté de
l'interpreteur de commande ?
merci, ça marche !
(j'en étais presque à recoder tout ça avec IPC::Open3 )
À (at) Mon, 26 Mar 2007 16:30:01 +0200,
gerbier écrivait (wrote):ce que je ne comprends pas, c'est pourquoi sans arguments, il
n'interprete pas "C:/Program" comme une commande et
"Files/tmp/essai2.pl" comme un argument ? une bizarreté de
l'interpreteur de commande ?
Tout simplement parce que s'il n'y a pas d'argument, perl ne passe pas
l'interpréteur de commandes (sur Windows) ou par le shell (sur
Unix). Ça évite tous les risques liés à ce passage. Vous êtes tombés
sur l'un des problèmes. Sachez que vous avez potentiellement le même
problème sur tous les arguments. Et là, ce ne sera peut-être pas
visible lors de l'exécution... Un solution pour être sûr et si vous
utilisez un perl récent, consiste à utiliser la syntaxe étendue de
open :
open mt $fh, "-|", "C:/Program Files/.../", $arg1, $arg2
or die "Can't lauch '...': $!n';
(j'en étais presque à recoder tout ça avec IPC::Open3 )
Ce serait une autre bonne solution (lire perlipc pour en savoir plus)
pour garantir le comportement.
À (at) Mon, 26 Mar 2007 16:30:01 +0200,
gerbier <eric_nospam_gerbier@meteo.fr.invalid> écrivait (wrote):
ce que je ne comprends pas, c'est pourquoi sans arguments, il
n'interprete pas "C:/Program" comme une commande et
"Files/tmp/essai2.pl" comme un argument ? une bizarreté de
l'interpreteur de commande ?
Tout simplement parce que s'il n'y a pas d'argument, perl ne passe pas
l'interpréteur de commandes (sur Windows) ou par le shell (sur
Unix). Ça évite tous les risques liés à ce passage. Vous êtes tombés
sur l'un des problèmes. Sachez que vous avez potentiellement le même
problème sur tous les arguments. Et là, ce ne sera peut-être pas
visible lors de l'exécution... Un solution pour être sûr et si vous
utilisez un perl récent, consiste à utiliser la syntaxe étendue de
open :
open mt $fh, "-|", "C:/Program Files/.../", $arg1, $arg2
or die "Can't lauch '...': $!n';
(j'en étais presque à recoder tout ça avec IPC::Open3 )
Ce serait une autre bonne solution (lire perlipc pour en savoir plus)
pour garantir le comportement.
À (at) Mon, 26 Mar 2007 16:30:01 +0200,
gerbier écrivait (wrote):ce que je ne comprends pas, c'est pourquoi sans arguments, il
n'interprete pas "C:/Program" comme une commande et
"Files/tmp/essai2.pl" comme un argument ? une bizarreté de
l'interpreteur de commande ?
Tout simplement parce que s'il n'y a pas d'argument, perl ne passe pas
l'interpréteur de commandes (sur Windows) ou par le shell (sur
Unix). Ça évite tous les risques liés à ce passage. Vous êtes tombés
sur l'un des problèmes. Sachez que vous avez potentiellement le même
problème sur tous les arguments. Et là, ce ne sera peut-être pas
visible lors de l'exécution... Un solution pour être sûr et si vous
utilisez un perl récent, consiste à utiliser la syntaxe étendue de
open :
open mt $fh, "-|", "C:/Program Files/.../", $arg1, $arg2
or die "Can't lauch '...': $!n';
(j'en étais presque à recoder tout ça avec IPC::Open3 )
Ce serait une autre bonne solution (lire perlipc pour en savoir plus)
pour garantir le comportement.
j'ai regardé perlfaq8
(ex :
http://perl.enstimac.fr/DocFr/perlfaq8.html#comment%20capturer%20la%20sortie%20stderr%20d'une%20commande%20externe)
et j'ai deux questions sur un code comme ci-dessous :
my($wtr, $rdr, $err);
$pid = open3($wtr, $rdr, $err, 'cmd', 'optarg', ...);
while(my $line = <$rdr>) {
...
}
waitpid($pid, 0);
- je ne vois pas de close : est-ce normal ?
- est-ce qu'il y a un inconvénient à ne lire qu'un seul des flux (ici
$rdr) ?
j'ai regardé perlfaq8
(ex :
http://perl.enstimac.fr/DocFr/perlfaq8.html#comment%20capturer%20la%20sortie%20stderr%20d'une%20commande%20externe)
et j'ai deux questions sur un code comme ci-dessous :
my($wtr, $rdr, $err);
$pid = open3($wtr, $rdr, $err, 'cmd', 'optarg', ...);
while(my $line = <$rdr>) {
...
}
waitpid($pid, 0);
- je ne vois pas de close : est-ce normal ?
- est-ce qu'il y a un inconvénient à ne lire qu'un seul des flux (ici
$rdr) ?
j'ai regardé perlfaq8
(ex :
http://perl.enstimac.fr/DocFr/perlfaq8.html#comment%20capturer%20la%20sortie%20stderr%20d'une%20commande%20externe)
et j'ai deux questions sur un code comme ci-dessous :
my($wtr, $rdr, $err);
$pid = open3($wtr, $rdr, $err, 'cmd', 'optarg', ...);
while(my $line = <$rdr>) {
...
}
waitpid($pid, 0);
- je ne vois pas de close : est-ce normal ?
- est-ce qu'il y a un inconvénient à ne lire qu'un seul des flux (ici
$rdr) ?
Oui et non... Le 'close' est implicite en fin de script. Mais on peut
aussi le gérer soi-même. Ceci étant les 'close' ne peuvent être fait
qu'après le 'waitpid' puisque tant que le processus fils est vivant il
peut encore écrire et même lorsqu'il est terminé, il peut encore
rester des choses à lire...
Oui et non... Le 'close' est implicite en fin de script. Mais on peut
aussi le gérer soi-même. Ceci étant les 'close' ne peuvent être fait
qu'après le 'waitpid' puisque tant que le processus fils est vivant il
peut encore écrire et même lorsqu'il est terminé, il peut encore
rester des choses à lire...
Oui et non... Le 'close' est implicite en fin de script. Mais on peut
aussi le gérer soi-même. Ceci étant les 'close' ne peuvent être fait
qu'après le 'waitpid' puisque tant que le processus fils est vivant il
peut encore écrire et même lorsqu'il est terminé, il peut encore
rester des choses à lire...
Tu pipotes très largement.
D'une part, ici, le close comme le wait sont faits après une boucle
attendant la fin de fichier sur le pipe. Quand la fin de fichier est reçue,
il est certain que le processus à l'autre bout ne peut plus écrire, donc le
close est sûr.
D'autre part, tant que le fichier n'a pas été fermé, le processus à l'autre
bout peut être bloqué en écriture : faire le wait avant le close provoquera
donc un deadlock. Au contraire, le close avant le wait tuera le processus à
l'autre bout avec un SIGPIPE, ce qui est préférable.
C'est encore plus vrai si le canal est bidirectionnel : même s'il a fermé en
écriture, le processus à l'autre bout peut attendre une fin de fichier en
lecture avant de se terminer.
Pour toutes ces raisons, il faut toujours fermer les pipes avant d'attendre
le processus fils.
Tu pipotes très largement.
D'une part, ici, le close comme le wait sont faits après une boucle
attendant la fin de fichier sur le pipe. Quand la fin de fichier est reçue,
il est certain que le processus à l'autre bout ne peut plus écrire, donc le
close est sûr.
D'autre part, tant que le fichier n'a pas été fermé, le processus à l'autre
bout peut être bloqué en écriture : faire le wait avant le close provoquera
donc un deadlock. Au contraire, le close avant le wait tuera le processus à
l'autre bout avec un SIGPIPE, ce qui est préférable.
C'est encore plus vrai si le canal est bidirectionnel : même s'il a fermé en
écriture, le processus à l'autre bout peut attendre une fin de fichier en
lecture avant de se terminer.
Pour toutes ces raisons, il faut toujours fermer les pipes avant d'attendre
le processus fils.
Tu pipotes très largement.
D'une part, ici, le close comme le wait sont faits après une boucle
attendant la fin de fichier sur le pipe. Quand la fin de fichier est reçue,
il est certain que le processus à l'autre bout ne peut plus écrire, donc le
close est sûr.
D'autre part, tant que le fichier n'a pas été fermé, le processus à l'autre
bout peut être bloqué en écriture : faire le wait avant le close provoquera
donc un deadlock. Au contraire, le close avant le wait tuera le processus à
l'autre bout avec un SIGPIPE, ce qui est préférable.
C'est encore plus vrai si le canal est bidirectionnel : même s'il a fermé en
écriture, le processus à l'autre bout peut attendre une fin de fichier en
lecture avant de se terminer.
Pour toutes ces raisons, il faut toujours fermer les pipes avant d'attendre
le processus fils.
Sauf qu'ici, il y a trois canaux (entrée standard, sortie standard et
sortie d'erreur).
Tout cela est vrai si on considère des opérations bloquantes. Mais à
partir du moment où il y a plusieurs canaux, sauf à maîtriser
parfaitement le fonctionnement des deux processus communicants, on ne
peut plus se reposer sur des opérations bloquantes.
Or, de manière standard, il n'existe pas de moyens de faire
simultanément des wait et des lectures/écritures non bloquants
Pour les canaux en lecture, s'il n'y a plus rien à lire c'est que le
canal a été fermé à l'autre bout. Le 'close' explicite est donc
nettement moins important.
Si on se place dans un contexte non-bloquant, ce n'est pas toujours
nécessaire ni possible.
Sauf qu'ici, il y a trois canaux (entrée standard, sortie standard et
sortie d'erreur).
Tout cela est vrai si on considère des opérations bloquantes. Mais à
partir du moment où il y a plusieurs canaux, sauf à maîtriser
parfaitement le fonctionnement des deux processus communicants, on ne
peut plus se reposer sur des opérations bloquantes.
Or, de manière standard, il n'existe pas de moyens de faire
simultanément des wait et des lectures/écritures non bloquants
Pour les canaux en lecture, s'il n'y a plus rien à lire c'est que le
canal a été fermé à l'autre bout. Le 'close' explicite est donc
nettement moins important.
Si on se place dans un contexte non-bloquant, ce n'est pas toujours
nécessaire ni possible.
Sauf qu'ici, il y a trois canaux (entrée standard, sortie standard et
sortie d'erreur).
Tout cela est vrai si on considère des opérations bloquantes. Mais à
partir du moment où il y a plusieurs canaux, sauf à maîtriser
parfaitement le fonctionnement des deux processus communicants, on ne
peut plus se reposer sur des opérations bloquantes.
Or, de manière standard, il n'existe pas de moyens de faire
simultanément des wait et des lectures/écritures non bloquants
Pour les canaux en lecture, s'il n'y a plus rien à lire c'est que le
canal a été fermé à l'autre bout. Le 'close' explicite est donc
nettement moins important.
Si on se place dans un contexte non-bloquant, ce n'est pas toujours
nécessaire ni possible.
Ça ne change rien à ce que j'ai dit : si on a reçu une fin de fichier, on
peut fermer, toujours.
Il suffit que l'un des deux processus soit asynchrone, il n'est pas
nécessaire que les deux le soient. Le plus souvent, le père sera asynchrone
et gérera les bizarreries, tandis que le fils est un simple filtre écrit
dans un cadre plus général.
Or, de manière standard, il n'existe pas de moyens de faire
simultanément des wait et des lectures/écritures non bloquants
Euh, si, ça s'appelle SIGCHLD.
Pour les canaux en lecture, s'il n'y a plus rien à lire c'est que le
canal a été fermé à l'autre bout. Le 'close' explicite est donc
nettement moins important.
Dans ce cas, on ne fait pas le wait non plus. Si on fait le wait, on doit
faire les close, et on doit les faire avant.
Si on se place dans un contexte non-bloquant, ce n'est pas toujours
nécessaire ni possible.
Je maintiens que c'est toujours possible.
La seule exception qu'on peut y faire, c'est quand le processus fils va
lui-même avoir des descendants qui vont lui survivre, et garder les pipes
ouverts. Dans tous les autres cas, c'est un bug de faire un wait avant
d'avoir fermé tous les canaux.
Ça ne change rien à ce que j'ai dit : si on a reçu une fin de fichier, on
peut fermer, toujours.
Il suffit que l'un des deux processus soit asynchrone, il n'est pas
nécessaire que les deux le soient. Le plus souvent, le père sera asynchrone
et gérera les bizarreries, tandis que le fils est un simple filtre écrit
dans un cadre plus général.
Or, de manière standard, il n'existe pas de moyens de faire
simultanément des wait et des lectures/écritures non bloquants
Euh, si, ça s'appelle SIGCHLD.
Pour les canaux en lecture, s'il n'y a plus rien à lire c'est que le
canal a été fermé à l'autre bout. Le 'close' explicite est donc
nettement moins important.
Dans ce cas, on ne fait pas le wait non plus. Si on fait le wait, on doit
faire les close, et on doit les faire avant.
Si on se place dans un contexte non-bloquant, ce n'est pas toujours
nécessaire ni possible.
Je maintiens que c'est toujours possible.
La seule exception qu'on peut y faire, c'est quand le processus fils va
lui-même avoir des descendants qui vont lui survivre, et garder les pipes
ouverts. Dans tous les autres cas, c'est un bug de faire un wait avant
d'avoir fermé tous les canaux.
Ça ne change rien à ce que j'ai dit : si on a reçu une fin de fichier, on
peut fermer, toujours.
Il suffit que l'un des deux processus soit asynchrone, il n'est pas
nécessaire que les deux le soient. Le plus souvent, le père sera asynchrone
et gérera les bizarreries, tandis que le fils est un simple filtre écrit
dans un cadre plus général.
Or, de manière standard, il n'existe pas de moyens de faire
simultanément des wait et des lectures/écritures non bloquants
Euh, si, ça s'appelle SIGCHLD.
Pour les canaux en lecture, s'il n'y a plus rien à lire c'est que le
canal a été fermé à l'autre bout. Le 'close' explicite est donc
nettement moins important.
Dans ce cas, on ne fait pas le wait non plus. Si on fait le wait, on doit
faire les close, et on doit les faire avant.
Si on se place dans un contexte non-bloquant, ce n'est pas toujours
nécessaire ni possible.
Je maintiens que c'est toujours possible.
La seule exception qu'on peut y faire, c'est quand le processus fils va
lui-même avoir des descendants qui vont lui survivre, et garder les pipes
ouverts. Dans tous les autres cas, c'est un bug de faire un wait avant
d'avoir fermé tous les canaux.