OVH Cloud OVH Cloud

popen et stderr

13 réponses
Avatar
meta
Bonjour,

J'utilise popen pour exécuter une commande ksh dont je redirige le stderr:
2> /dev/null.

Si le résultat de la commande est bon, aucun message n'est affiché sur
stdout car il est récupéré via le descripteur dans une chaîne de caractères
C et c'est ce que je veux.

Si le résultat n'est pas bon, le message d'erreur de la commande s'affiche
systématiquement malgré la redirection.

De plus, ni le message provenant du perror ni celui du printf (exécutés en
cas de résultat ko) ne sont affichés que ce soit sur le stderr ou le stdout
(pourtant j'ai bien fermé le descripteur du popen avant). Je voudrais
l'inverse ! C.à.d que les messages C soient affichés, mais pas ceux du ksh.

Le premier problème se résout en fermant le stderr mais je voudrais éviter
cela. Peut-on malgré tout imaginer une fermeture temporaire de stderr dont
aura préalablement dup2-liqué le descripteur pour le réouvrir après, mais je
n'ai pas eu le temps de faire la manip ? Existe-t'il une autre solution (je
préfèrerais) ?

Pour le second, je n'ai pas trouvé.

Merci pour toute aide.

3 réponses

1 2
Avatar
espie
In article ,
Bruno Ducrot wrote:
On 07-07-2012, Marc Espie wrote:

SANS GESTION D'ERREUR:



Je ne sais pas si c'est une bonne idée de présenter un code
sans gestion d'erreur, mais bon. Pourquoi pas ?



Pour des raisons pedagogiques, si, a mon sens.
- d'une part, dans ce cas precis, il y a des erreurs possibles partout.
- d'autre part, dans la vraie vie, on ne va a peu pres jamais utiliser
directement tous ses appels systeme. Sur un vrai programme, on va
systematiquement mettre une fonction de gestion d'erreur autour, et ne
plus appeler les fonctions systeme.

Genre:

int fd[2];

pipe(fd);




^ca peut echouer
int pid = fork();




^ca peut echouer
if (pid == 0) { /* fils */
close(2);
if (fd[1] != 1) {
dup2(fd[1], 1);
close(fd[1]);
close(fd[0]);




^ tout ces appels peuvent echouer.
execl("/bin/sh", "sh", "-c", "ls toto*|head -1", NULL);



Je rajoute systématiquement un exit() ici, juste au cas où exec?()
échoue.


Ben oui, comme tout le monde.

... mais bon, dans ce cas, il faut AUSSI recuperer le statut du wait et
le traiter, sinon ca n'a aucun sens.


} else { /* papa */
close(fd[1]);
FILE *f = fdopen(fd[0], "r");
fgets sur f....
fclose(f);
int status;
waitpid(pid, &status, 0);
}




Et les joies de la gestion d'erreur sur le fdopen, le fclose, et le waitpid.


A chaque fois, au minimum, faudra faire un truc du genre:
if (pipe(fd) != 0) {
perror("pipe");
exit(1);
}

bref, 4 fois plus long.

Ou alors, en vrai, on definit ses propres fonctions, et pedagogiquement,
c'est pas tip-top non plus, vu que chacun a "ses" propres noms de fonctions,
"ses" propres conventions. Deja vu ca dans des bouquins: generalement
pas fan, c'est le modele du gugus qui commence par "redefinir" son Unix/C
dans la preface, et le reste du bouquin, du coup, n'est pas lisible sans
la preface...

Si on veut insister sur la gestion d'erreur, il convient de rappeler qu'il
ne faut jamais etre "optimiste": si un appel systeme est marque comme
pouvant echouer, alors il VA echouer... et toujours au moment ou on se
disait "ca n'est pas possible"... ca prend plus de temps de trouver le bug...
ou de se poser la question "est-ce que cet appel peut echouer ?" du coup,
c'est plus economique pour le cerveau de supposer que tout peut echouer
(et ca evite les bugs "impossibles", ou du moins ca permet de les
detecter du premier coup).
Avatar
Bruno Ducrot
On 08-07-2012, meta wrote:
Heu.. ben comme ca, je ne suis pas super en forme je dirais que c'est
logique. Tu as redirigé le stderr de la partie "head". Celle du ls
est toujours assignée au terminal, et le "ls" est libre de te dire
qu'il n'a rien trouvé pour "toto" et ca arrive à l'écran.



Oui en effet. J'avais bien tenté d'encadrer l'ensemble de la commande mais
je n'ai pas utilisé ce qu'il fallait.

Le "head -1" te sert à récupérer la 1ere ligne je pense. Pourquoi tu
ne gère pas cela dans la boucle lisant le flux issu du "ls toto*" ?



Parce que je n'ai pas donné la commande complète: ls -t toto*. En fait je
voulais le toto le plus récent et je n'avais pas envie de m'embêter à le
gérer en C, pas le temps non plus :) Sinon il y avait effectivement la
solution de tout faire en C que tu décris mais là encore j'étais trop juste
en temps (Je sais c'est pas dur à faire mais quand on vous met la pression
avec un temps ridiculement court pour tout faire...).




Avec l'option '-t', tu obtiens le toto* à avoir été modifié en dernier,
et non pas forcément le plus récent.

Est-ce bien ce que tu veux ?

A plus,

--
Bruno Ducrot

A quoi ca sert que Ducrot hisse des carcasses ?
Avatar
meta
Avec l'option '-t', tu obtiens le toto* à avoir été modifié en dernier,
et non pas forcément le plus récent.

Est-ce bien ce que tu veux ?



Dans le cas où je m'en sers cela revient au même, mais merci quand même.
1 2