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 :

[Linux]comment intercepter le stdin ?


Sujet :

POSIX C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Par défaut [Linux]comment intercepter le stdin ?
    Bonjour

    J' ai besoin d'intercepter le stdin dans mon programme d'un processus fils
    exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    pid_t pid = fork();
    if (pid == 0)
     { 
    .....
    ....
    execvp("tr","a-z","A-Z");  //commande unix pour convertir une chaine en Maj
    }
    else if (pid == 1) {
    wait(&staus)
    .....
    .... comment recupere l'entré passé a la commande tr dans le terminal ???
    }
    je veux récupérer le text taper a la commande "tr" pour l'utliser plus tard dans le processus Pere sans blocké le stdin??

    Merci

  2. #2
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Ton utilisation de fork() est erronée, on l'utilise comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    pid_t pid = fork();
     
    if(pid == -1)
    {
       /* error */
    }
    else if(pid == 0)
    {
       /* son */
    }
    else
    {
       /* father : pid = son's pid */
    }
    cordialement

  3. #3
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Si tu veux capturer ce que l'utilisateur envoie à la commande tr, la seule solution est de lire toi-même (dans le process père) stdin, puis de passer les données lues au process fils (tr) via un pipe connecté au stdin de de tr. Tu auras besoin de pipe() (avant le fork) et de dup2() (dans le process fils, entre le fork et le exec).

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Par défaut
    Citation Envoyé par matafan Voir le message
    Si tu veux capturer ce que l'utilisateur envoie à la commande tr, la seule solution est de lire toi-même (dans le process père) stdin, puis de passer les données lues au process fils (tr) via un pipe connecté au stdin de de tr. Tu auras besoin de pipe() (avant le fork) et de dup2() (dans le process fils, entre le fork et le exec).
    Je comprend ce que vous voulez dire...et tous mes fork() et pipe() son bien configurer....
    mais, admettons que je veut passer plusieurs texte a la commande "tr" jusqu'a la fermeture de stdin (^D)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    $ tr a-z A-Z
    hello       <-
    HELLO     
    bonjour    <-
    BONJOUR
    pomme    <-
    POMME
    ^D
    $
    ici le process pere recupere : hello,bonjour , pomme.
    j'ai vue dans des forum qu'ils parlent du poll(). mais je comprend pas comment l'utiliser.....

  5. #5
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Tout ça n'est pas très clair...
    Commence par nous expliquer ce que tu souhaites réaliser, sans parler de programmation, ensuite on verra s'il y a vraiment de besoin de spawner un nouveau processus et de faire aussi compliqué.

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Par défaut
    Citation Envoyé par nicolas.sitbon Voir le message
    Tout ça n'est pas très clair...
    Commence par nous expliquer ce que tu souhaites réaliser, sans parler de programmation, ensuite on verra s'il y a vraiment de besoin de spawner un nouveau processus et de faire aussi compliqué.
    j'ai besoin permettre a l'utilisateur de passer la commande "tr" a mon programme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $monprogramme tr a-z A-Z
    et par la suite mon programme doit intercepter tous les mots taper dans la commande "tr" par l'utilisateur et les afficher par la suite.

  7. #7
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Dans ce cas c'est à ton programme (le process parent) de détecter les retours chariots, et d'envoyer à ce moment là les données reçues au process fils.

    Note que cette approche suppose que la commande "tr" affiche ses données après chaque retour chariot, ce qui n'est pas forcément garanti. La seule façon d'être sûr du résultat et de forker une nouvelle commande "tr" pour chaque ligne.

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Par défaut
    Citation Envoyé par matafan Voir le message
    Dans ce cas c'est à ton programme (le process parent) de détecter les retours chariots, et d'envoyer à ce moment là les données reçues au process fils.

    Note que cette approche suppose que la commande "tr" affiche ses données après chaque retour chariot, ce qui n'est pas forcément garanti. La seule façon d'être sûr du résultat et de forker une nouvelle commande "tr" pour chaque ligne.
    et comment tu peut detecter le retour chariot dans ce cas ?

  9. #9
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    toujours pas clair...
    Citation Envoyé par Edw@rd Voir le message
    et par la suite mon programme doit intercepter tous les mots taper dans la commande "tr" par l'utilisateur et les afficher par la suite.
    Que veut dire intercepter pour toi? les récupérer et empêcher leur affichage? autre chose?
    taper un mot dans une commande ne veut pas dire grand chose.
    voici comment fonctionne la commande tr:
    elle reçoit les arguments sur sa ligne de commande qui lui indique le type de traduction a effectué. elle reçoit sur son entrée standard les données à traduires sous forme de ligne. A chaque ligne entrée, elle affiche le résultat de la traduction sur sa sortie standard.
    Voilà ça ça ne changera pas, maintenant, pour ton programme, qu'attend il sur sa ligne de commande, sur son entrée standard, et quel résultat doit il produire sur sa sortie standard (si résultat il y a biensûr)?

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Par défaut
    Citation Envoyé par nicolas.sitbon Voir le message
    toujours pas clair...

    Que veut dire intercepter pour toi? les récupérer et empêcher leur affichage? autre chose?
    taper un mot dans une commande ne veut pas dire grand chose.
    voici comment fonctionne la commande tr:
    elle reçoit les arguments sur sa ligne de commande qui lui indique le type de traduction a effectué. elle reçoit sur son entrée standard les données à traduires sous forme de ligne. A chaque ligne entrée, elle affiche le résultat de la traduction sur sa sortie standard.
    Voilà ça ça ne changera pas, maintenant, pour ton programme, qu'attend il sur sa ligne de commande, sur son entrée standard, et quel résultat doit il produire sur sa sortie standard (si résultat il y a biensûr)?
    par intercepter : juste récupérer le texte passé a tr et les afficher par la suite (tous les mots).
    mon programme juste lance un processus avec le tr et n'attend rien sur son entrée standard....

  11. #11
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Citation Envoyé par Edw@rd Voir le message
    et comment tu peut detecter le retour chariot dans ce cas ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    while ( (int c = getchar()) != EOF ) {
        /* Ajouter c aux données */
        if (c == '\n') {
            /* Envoyer les données */
        }
    }

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Par défaut
    Citation Envoyé par matafan Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    while ( (int c = getchar()) != EOF ) {
        /* Ajouter c aux données */
        if (c == '\n') {
            /* Envoyer les données */
        }
    }
    je suis d'accord avec ce code, mais le getchar() ici va blocké l'entrée standard....
    dans mon cas je veut pas de blockage....

  13. #13
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Citation Envoyé par Edw@rd Voir le message
    par intercepter : juste récupérer le texte passé a tr et les afficher par la suite (tous les mots).
    mon programme juste lance un processus avec le tr et n'attend rien sur son entrée standard....
    Comment fait ton programme pour intercepter si ce n'est pas sur son entrée standard?

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Par défaut
    Citation Envoyé par nicolas.sitbon Voir le message
    Comment fait ton programme pour intercepter si ce n'est pas sur son entrée standard?
    c'est ca ce que je cherche a resoudre...
    permettre a mon programme "d'espionner" l'entrée standard du "tr" sans blocké.

  15. #15
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Ok je comprends mieux le besoin et le soucis, je te conseille un peu de lecture sur les pseudos terminaux pour commencer : http://www.unixgarden.com/index.php/...es-interactifs.

  16. #16
    Membre averti
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Par défaut
    Citation Envoyé par nicolas.sitbon Voir le message
    Ok je comprends mieux le besoin et le soucis, je te conseille un peu de lecture sur les pseudos terminaux pour commencer : http://www.unixgarden.com/index.php/...es-interactifs.
    Merci pour le lien

  17. #17
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Citation Envoyé par Edw@rd Voir le message
    je suis d'accord avec ce code, mais le getchar() ici va blocké l'entrée standard....
    dans mon cas je veut pas de blockage....
    Je dois mal comprendre ce que tu veux faire, mais non, il ne va pas "bloquer l'entrée standard". La lecture s'arrêtera quand l'utilisateur entrera un ^D, comme dans ton exemple.

  18. #18
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Bon je crois que tu n'as pas compris ma méthode, donc je te donne le code. Pose des questions si tu ne comprend pas. Note que c'est juste pour l'exemple, il y a des détails à améliorer (le buf de taille fixe, et le write() qui ne suffit pas pour garantir l'envoie des données - il faudrait une boucle).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/wait.h>
     
    #define READ_END  0
    #define WRITE_END 1
     
    int
    main(int argc, char **argv)
    {
    	int pipefd[2], c, i = 0, status;
    	char buf[4096];
    	pid_t pid;
     
    	/* This pipe will be connected to our child's stdin */
    	if (pipe(pipefd)) {
    		perror("pipe");
    		return 1;
    	}
     
    	pid = fork();
     
    	if (pid == -1) { /*** Error ***/
     
    		perror("fork");
    		return 0;
     
    	} else if (pid == 0) { /*** Child ***/
     
    		/* Close write end of pipe */
    		close(pipefd[WRITE_END]);
     
    		/* Connect read end of pipe to stdin */
    		if (-1 == dup2(pipefd[READ_END], STDIN_FILENO)) {
    			perror("dup2");
    			return 1;
    		}
    		close(pipefd[READ_END]);
     
    		/* Execute user-provided command */
    		execvp(argv[1], argv + 1);
    		perror("execvp");
    		return 1;
     
    	} else { /*** Parent ***/
     
    		/* Close read end of pipe */
    		close(pipefd[READ_END]);
     
    		/* Read data on stdin, sending them to the child process
    		 * every time a newline is read */
    		while ( (c = getchar()) != EOF ) {
    			buf[i++] = c;
    			if (c == '\n') {
    				if (i != write(pipefd[WRITE_END], buf, i)) {
    					perror("write");
    					return 1;
    				}
    				i = 0;
    			}
    		}
    		if (c != EOF) {
    			perror("getchar");
    			return 1;
    		}
     
    		/* Closing the pipe will signal EOF in the child */
    		close(pipefd[WRITE_END]);
     
    		/* Wait for child */
    		wait(&status);
    		if ( (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0) ) {
    			fputs("Child process terminated abnormally\n", stderr);
    			return 1;
    		}
    	}
     
    	return 0;
    }
    Et ça donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $ ./wrapper tr a-z A-Z
    hello
    HELLO
    bonjour
    BONJOUR
    pomme
    POMME    <- Ctrl-d
    $

  19. #19
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Citation Envoyé par matafan Voir le message
    Bon je crois que tu n'as pas compris ma méthode, donc je te donne le code. Pose des questions si tu ne comprend pas. Note que c'est juste pour l'exemple, il y a des détails à améliorer (le buf de taille fixe, et le write() qui ne suffit pas pour garantir l'envoie des données - il faudrait une boucle).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/wait.h>
     
    #define READ_END  0
    #define WRITE_END 1
     
    int
    main(int argc, char **argv)
    {
    	int pipefd[2], c, i = 0, status;
    	char buf[4096];
    	pid_t pid;
     
    	/* This pipe will be connected to our child's stdin */
    	if (pipe(pipefd)) {
    		perror("pipe");
    		return 1;
    	}
     
    	pid = fork();
     
    	if (pid == -1) { /*** Error ***/
     
    		perror("fork");
    		return 0;
     
    	} else if (pid == 0) { /*** Child ***/
     
    		/* Close write end of pipe */
    		close(pipefd[WRITE_END]);
     
    		/* Connect read end of pipe to stdin */
    		if (-1 == dup2(pipefd[READ_END], STDIN_FILENO)) {
    			perror("dup2");
    			return 1;
    		}
    		close(pipefd[READ_END]);
     
    		/* Execute user-provided command */
    		execvp(argv[1], argv + 1);
    		perror("execvp");
    		return 1;
     
    	} else { /*** Parent ***/
     
    		/* Close read end of pipe */
    		close(pipefd[READ_END]);
     
    		/* Read data on stdin, sending them to the child process
    		 * every time a newline is read */
    		while ( (c = getchar()) != EOF ) {
    			buf[i++] = c;
    			if (c == '\n') {
    				if (i != write(pipefd[WRITE_END], buf, i)) {
    					perror("write");
    					return 1;
    				}
    				i = 0;
    			}
    		}
    		if (c != EOF) {
    			perror("getchar");
    			return 1;
    		}
     
    		/* Closing the pipe will signal EOF in the child */
    		close(pipefd[WRITE_END]);
     
    		/* Wait for child */
    		wait(&status);
    		if ( (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0) ) {
    			fputs("Child process terminated abnormally\n", stderr);
    			return 1;
    		}
    	}
     
    	return 0;
    }
    Et ça donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $ ./wrapper tr a-z A-Z
    hello
    HELLO
    bonjour
    BONJOUR
    pomme
    POMME    <- Ctrl-d
    $
    ça n'est pas garanti de fonctionner avec toutes les implémentations de tr, tu dois utiliser un pseudo terminal pour ne pas te retrouver dans une position d'interblocage.

  20. #20
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Je ne vois pas comment on pourrait avoir un interblocage ? Ca pourrait arriver si le programme père lisait la sortie du programme fils, mais ce n'est pas le cas ici. Et même dans ce cas, on pourrait régler le problème avec un poll() ou un select().

Discussions similaires

  1. [Linux] comment installer GLUT
    Par Mathieu.J dans le forum GLUT
    Réponses: 5
    Dernier message: 28/09/2012, 17h39
  2. [oracle9i-Linux] Comment vider un UNDO tablespace
    Par Loïck dans le forum Oracle
    Réponses: 8
    Dernier message: 03/12/2009, 13h53
  3. Réponses: 7
    Dernier message: 27/06/2005, 22h05
  4. Réponses: 4
    Dernier message: 26/06/2005, 23h28

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