Passer stdin à une commande passé au shell sur stdin [shell] - Shell/Batch - Programmation
Marsh Posté le 02-06-2008 à 13:58:03
C'est ce que je craignais Faudra que j'explique exactement ce que je fais.
Marsh Posté le 03-06-2008 à 09:46:19
En fait voilà : je fais un programme en C qui doit générer des lignes de commandes à partir de règles qui se trouvent dans un fichier xml, et les faire exécuter au shell. Pour ce faire j'ai décidé de passer la ligne de commande sur l'entrée standard du shell, parce que c'est la solution la plus robuste. Les autres solutions envisageables, mais moins bonnes, sont :
Donc, j'ai décidé de passer la ligne de commande sur l'entrée standard du shell : pipe, dup2, fork, exec("/usr/bin/ksh" ), puis j'écris la commande dans le pipe.
Seulement voilà, parfois, j'ai besoin d'envoyer des données sur l'entrée standard de ma ligne de commande. Si j'utilisais "ksh -c" ou "ksh tmp_file" je n'aurais pas de problème, il suffirait d'envoyer les données sur l'entrée standard du shell, et elles seraient consommées par la ligne de commande. Mais avec la solution retenues ce n'est pas possible, car c'est le shell lui même qui consomme données de son entrée standard, pour les interpréter.
Au final, ma solution bancale c'est de continuer à envoyer ma ligne de commande sur l'entrée standard du shell quand je n'ai pas besoin d'envoyer de données à l'entrée standard de la ligne de commande. Par contre, quand j'ai besoin d'envoyer des données à l'entrée standard de ma ligne de commande, je prendrais la solution du fichier temporaire, et j'enverrais les données sur l'entrée standard du shell.
Marsh Posté le 03-06-2008 à 09:49:25
OK mais bon comme tu dis, vu que la solution choisie est bidon, c'est forcément bancale ensuite. Question à 1000PO: t'as vraiment besoin de passer toutes tes commandes dans un shell et dans le même ?
Marsh Posté le 03-06-2008 à 09:57:24
Non, chaque ligne de commande est exécutée dans un nouveau shell.
Marsh Posté le 03-06-2008 à 10:01:56
bah alors tu t'en fous du shell, il sert à rien, exécute directement la commande.
Marsh Posté le 03-06-2008 à 10:16:23
Taz a écrit : bah alors tu t'en fous du shell, il sert à rien, exécute directement la commande. |
Je ne comprend pas l'interet d'un nouveau shell sauf peut être si tu as des variables d'environement dans tes programmes.
Marsh Posté le 03-06-2008 à 10:22:48
ReplyMarsh Posté le 03-06-2008 à 10:30:25
Taz a écrit : bah ça change rien, l'environnement suit toujours, shell ou pas. |
Je pensait plutot a un conflit entre les applications qui utilisent les memes variables d'environement.
Marsh Posté le 03-06-2008 à 10:35:25
bah l'environnement s'hérite, les modifications ne se propagent pas de fils en père.
Marsh Posté le 03-06-2008 à 11:25:14
J'ai besoin d'exécuter un shell car mes lignes de commandes sont des expressions shells. Elles peuvent contenir des redirections, des constructions complexes... Que je ne peux pas interpréter moi même. Donc il faut que je les fasse exécuter par un shell.
Marsh Posté le 03-06-2008 à 11:35:22
Ah ah magnifique, j'ai une solution assez intéressante
Je passe ma ligne de commande sur le stdin du shell, comme d'hab. Par contre, les données que je veux envoyer à ma ligne de commande, je les passe au shell sur le file descriptor 42. Ensuite en interne il suffit que j'entoure la ligne de commande avec "{ ligne_de_commande; } <&42" et le tour est joué, ma ligne de commande lit les données qui arrivent sur le fd 42. Plus crade tu meurs
Edit : <&42, pas <42
Marsh Posté le 03-06-2008 à 11:41:40
J'allais justement te proposer une solution de ce type.
Ca ne me semble pas crade du tout, mais la maniere logique de proceder dans ce contexte: puisque les fd standards ne sont pas dispo (a cause de ton echo), en creer d'autres et les utiliser.
A+,
Marsh Posté le 03-06-2008 à 11:44:27
Oui mais bon utiliser un numéro de fd hardcodé (42) c'est pas super.
Marsh Posté le 03-06-2008 à 12:40:30
Pourquoi les fichiers temporaires c'est pas génial au fait ?
Marsh Posté le 03-06-2008 à 13:11:25
Les fichiers temporaires c'est pas super niveau perf je pense. Mon truc doit exécuter des tas de commandes en raffale. La sécurité c'est pas forcément génial non plus, quoi qu'avec mktemp et des droits très restrictifs ça doit passer.
Enfin je pense qu'au final je vais prendre la solution du fd 42, sauf que j'étais un peu bête... Pas besoin de hardcoder un fd à utiliser, il suffit de générer la chaine "<&n" avec comme n le file descriptor du coté lecture du pipe.
Pour ceux que ça intéresse j'ai codé un petit programme de test qui montre comment ça marche. Le premier argument est la ligne de commande, le deuxième argument est la chaine qu'on veut envoyer à la ligne de commande :
Code :
|
A l'exécution ça donne par exemple :
$ ./shexec "cat > out" "How you doin'" |
Et ça marche parfaitement
Marsh Posté le 03-06-2008 à 13:32:13
le problème c'est que tu squatte un descripteur.
Les fichiers temporaires:
- niveau sécurité, y a pas vraiment de problème avec les bons droits. Ou créer tes fichiers dans un dossier spécifique
- niveau perf: optimisation prématurée. Est-ce que tu as un problèmes de perf ? Avec un FS moderne, ton fichier temporaire, il ne touchera jamais le disque, il restera en cache.
En solution intermédiaire, tu as les tubes nommés.
Ton code est pas top puisque tu ne vérifies pas le retour des write.
Marsh Posté le 03-06-2008 à 14:31:41
Mon code c'est un programme de test pour valider l'idée, il vérifie déjà bien trop de choses
Marsh Posté le 02-06-2008 à 13:44:58
Je voudrait savoir si vous voyez un moyen de passer des données sur l'entrée standard d'une commande, sachant que la commande en question est passée au shell via l'entrée standard du shell. Par exemple considérons la commande suivante :
cat > myfile
Evidemment comma ça elle ne fait pas grand chose, elle est faite pour lire des données sur stdin et les mettre dans un fichier. Elle pourrait par exemple être utilisée comme ça (oui je sais ça parrait bizarre, mais il y a une bonne raison pour laquelle je veux faire ce genre de choses) :
echo "my data" | cat > myfile
Pas de problèmes... Maintenant, imaginer que la commande n'est pas tappée en live dans un shell, ni écrite dans un fichier pour être exécutée, ni passée au shell avec -c, mais qu'elle est passée au shell sur stdin, comme ça :
echo "cat > myfile" | sh
Et là paf, problème : comme le stdin du shell est utilisé pour passer la commande à exécuter, je ne peux plus l'utiliser pour passer ls données qui doivent être consommées par le cat.
Donc voilà, je cherche un moyen de passer des données à l'entrée standard d'une commande, quand la commande elle même est passée au shell via l'entrée standard. J'imagine vaguement qu'on peut faire quelque chose en passant des données au shell sur le file descriptor 3 par exemple, et faire en sorte que la commande prennent son entrée standard sur le fd 3... Mais en pratique je ne vois pas trop comment faire.
Message édité par matafan le 02-06-2008 à 13:46:27