IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

POSIX C Discussion :

stdin et pipe


Sujet :

POSIX C

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    77
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 77
    Points : 56
    Points
    56
    Par défaut stdin et pipe
    Bonjour,
    J'aimerais fabriquer un pipe en C.
    J'ai quasi fait tout le code, il ne me manque plus qu'à trouver une petite chose...
    Et un petit exemple sera plus simple pour comprendre.

    Admettons que mon pipe soit :
    avec le fichier test.sh qui contient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    echo "http://www.developpez.net/"
    Je récupèrerai donc l'adresse web que j'entrerai en paramètre de firefox.

    Voilà, le seul problème est que je ne sais pas comment récupérer le texte issu de la première partie du pipe (ici, l'adresse web)...

    Auriez-vous la solution ?!
    Petite précision au cas où, je travaille sous linux.

    Merci par avance

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 369
    Points
    50 369
    Par défaut
    Il faut pour cela que le programme dans lequel tu "pipe" tes données ait été prévu pour lire des données sur stdin en entrée.

    Je ne suis pas sûr (mais cela reste à confirmer) que firefox sache le faire.

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 410
    Points : 23 809
    Points
    23 809
    Par défaut
    Citation Envoyé par knice Voir le message
    Admettons que mon pipe soit :
    avec le fichier test.sh qui contient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    echo "http://www.developpez.net/"
    Je récupèrerai donc l'adresse web que j'entrerai en paramètre de firefox.
    Firefox va ouvrir les pages que tu lui as passées en argument, sur sa ligne de commande, et pas ce qu'il va lire depuis le tube. Si c'est ce que tu cherches à faire (en Shell), il faut utiliser le caractère « ` » ou bien les parenthèses « $() » en bash. Exemple :
    Ça fonctionnera avec tous les programmes. Voici aussi du côté de xargs.

    Voilà, le seul problème est que je ne sais pas comment récupérer le texte issu de la première partie du pipe (ici, l'adresse web)... :pleure
    Un tube s'exploite comme un fichier ordinaire. En l'occurence, quand tu lances deux commandes avec un pipe en Shell, tu lies la sortie standard de la première avec l'entrée standard de la seconde. Donc, pour lire ce qui provient de ton pipe, ben tu lis l'entrée standard, tout simplement, avec les commandes de base que tu as apprises dans tes cours ou tutoriels de C.

    C'est à ça que ça sert d'ailleurs : faire en sorte que le programme n'ait pas à se soucier explicitement de la provenance de ses données. Par défaut, elles viennent du clavier. Tu verras plus tard que les combinaisons de touches style Ctrl-D n'ont pas été choisies au hasard et sont liées à ce même concept.

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    77
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 77
    Points : 56
    Points
    56
    Par défaut
    Merci pour vos réponses.

    Petite précision :
    je ne veux pas le faire que pour firefox.
    J'aimerais par exemple aussi pouvoir faire un truc du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ls -l /usr/bin | grep fi*
    Ma démarche est la suivante :
    - je lance le " ls -l /usr/bin " ( avec un execvp(...) )
    - J'AIMERAIS récupérer ce que renvoie la commande précédente ( je ne sais pas comment )
    - je mets ce que je récupère en paramètres de " grep fi*" ( toujours avec un execvp )

    Et donc, je bloque sur la 2ème partie. Je ne sais pas quelle commande utiliser pour récupérer ce qu'il sort de la première commande... (donc ce qu'il y a dans la sortie standard...)

    Si vous aviez une réponse... ( je sens que Obsidian, tu connais le truc... )

    Merci par avance !

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 410
    Points : 23 809
    Points
    23 809
    Par défaut
    Citation Envoyé par knice Voir le message
    Ma démarche est la suivante :
    - je lance le " ls -l /usr/bin " ( avec un execvp(...) )
    - J'AIMERAIS récupérer ce que renvoie la commande précédente ( je ne sais pas comment )
    - je mets ce que je récupère en paramètres de " grep fi*" ( toujours avec un execvp )

    Et donc, je bloque sur la 2ème partie. Je ne sais pas quelle commande utiliser pour récupérer ce qu'il sort de la première commande... (donc ce qu'il y a dans la sortie standard...)
    D'accord. Donc, déjà tu lances des programmes avec exec..(). Détail non négligeable.

    Ça reste confus mais je crois que tu te méprends sur un léger détail : lorsque tu lances « commande1 | commande2 » (sous Unix, en tout cas), les deux processus sont lancés simultanément ! Et la sortie standard de la première est redirigée en temps réel dans l'entrée standard de la seconde.

    Si tu veux simuler ce que fais le Shell, donc, il y a deux cas de figures :


    1) Tu cherches à ouvrir un seul programme et le piper (en lecture ou en écriture) avec le processus en cours d'exécution. Il existe un raccourci : popen().


    2) Tu cherches à refaire tout le cheminement pour toi et/ou lancer deux programmes distincts indépendament du tien, et dans ce cas, il faut :

    - Créer un tube avec pipe(). La fonction te renvoie deux descripteurs de fichiers, qui correspondent respectivement à l'entrée et à la sortie du tube.

    - Forker deux fois, pour créer deux fils, dont les images seront remplacées par celles des programmes que tu veux lancer.

    - À ce moment, chaque fils a hérité des deux descripteurs. Le premier doit refermer manuellement celui qui correspond à la lecture, et le second, celui qui correspond à l'écriture.

    - Dès lors, tu as un tube ouvert en bonne et due forme entre tes deux processus. Mais ce serait mieux si ces descripteurs prenaient la place des flux standards. Il faut donc refermer d'abord lesdits flux standards, puis s'arranger pour que le numéro du descripteur que tu as ouvert soit celui de ces flux standards, soit 0 (pour stdin), 1 (pour stdout) ou 2 (pour stderr). Et pour cela, tu vas utiliser dup2(). Mais c'est mieux si tu utilises les symboles STDIN_FILENO, STDOUT_FILENO ou STDERR_FILENO.

    - dup2() a dupliqué tes descripteurs (et non modifié). Chaque fils doit refermer l'original.

    - À ce stade, le montage est terminé et les deux processus sont reliés par leur sortie et leur entrée standard. Tu n'as plus qu'à lancer execvp() de chaque côté pour démarrer les programmes (qui ne sauront même pas qu'ils sont pipés entre eux, ce qui est l'effet recherché).

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 410
    Points : 23 809
    Points
    23 809
    Par défaut
    Complément de réponse :

    Citation Envoyé par knice Voir le message
    je ne veux pas le faire que pour firefox.
    J'aimerais par exemple aussi pouvoir faire un truc du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ls -l /usr/bin | grep fi*
    Les opérateurs ` ` ou $( ) font partie du Shell, pas de Firefox. L'exemple en question s'écrira donc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    grep fi* `ls -l /usr/bin`
    Et pour être plus propre (c'est à dire transformer tous tes retours à la ligne en espaces uniques) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    grep fi* `ls -l /usr/bin | xargs`
    Et dans ce cas particulier, tu n'as pas besoin de ls. L'étoile et autres caractères-jokers sont développés par le Shell avant de lancer la commande. Donc, un :

    Sans opérateur de sous-shell, ni tube, ni quoi que ce soit, suffit largement.

    Ma démarche est la suivante :
    - je lance le " ls -l /usr/bin " ( avec un execvp(...) )
    - J'AIMERAIS récupérer ce que renvoie la commande précédente ( je ne sais pas comment )
    - je mets ce que je récupère en paramètres de " grep fi*" ( toujours avec un execvp )
    Si tu veux le faire en deux fois, explicitement, tu ouvres ton ls avec un popen(), qui te renvoie un descripteur de fichier. Tu lis le contenu son contenu comme avec un fichier ordinaire. Ce que tu en tireras sera ce qui a été renvoyé par le programme lancé par popen(). Tu peux le faire de la même façon à la main en adaptant les étapes de mon précédent commentaire.

    Ensuite, pour passer ce truc en argument de grep ou d'autre chose, ben tu utilises un buffer suffisament grand pour y écrire une ligne de commande, tu construis celle-ci en utilisant sprintf(), et tu passes ton buffer à ta fonction execvp().


    Dernière astuce : si ce que tu veux faire est espionner ce qui passe dans le tube, ou simplement en garder la trace, il existe la commande tee.

    Bon courage.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    77
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 77
    Points : 56
    Points
    56
    Par défaut Parfait
    Obsidian, tu as tout compris !
    Réponse parfaite !

    Il n'y a plus qu'à coder ça ^^

    Merci beaucoup !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème de lecture de stdin lors de pipe avec tail -f
    Par Samb95 dans le forum Général Python
    Réponses: 7
    Dernier message: 17/08/2010, 14h58
  2. [Named Pipe]Redirection de STDIN et STDOUT
    Par homeostasie dans le forum Windows
    Réponses: 5
    Dernier message: 22/04/2009, 21h42
  3. Stdin/Pipes et intégration MPlayer à VB6
    Par Yop dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 10/10/2008, 15h27
  4. pipe stdin stdout
    Par onaipadesmickey dans le forum Linux
    Réponses: 1
    Dernier message: 22/08/2007, 17h20
  5. récupèrer stdin venant d'un pipe
    Par julien.63 dans le forum POSIX
    Réponses: 19
    Dernier message: 13/06/2007, 12h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo