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

C Discussion :

Mini-shell probleme avec pipe


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2011
    Messages : 6
    Par défaut Mini-shell probleme avec pipe
    Bonjour,

    Je suis débutant en c. J'ai écrit un mini-shell en c que je souhaite compléter, pouvant ainsi utiliser des pipes. Seulement voilà, le code c semble fonctionner puisqu'il m'affiche la bonne réponse, mais aussi-tôt une commande lancée avec un pipe, je suis éjecté du mini-shell. Je galère depuis une bonne semaine sur ce problème sans pouvoir trouver une solution.

    Ci-après mon code:
    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
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    int main(int argc, char * argv[])
    {  	decouper(getenv("PATH"), ":", dirs, MaxDirs);			
      	for(printf(PROMPT); fgets(ligne, sizeof ligne, stdin) != 0; printf(PROMPT))
    	{	decouper(ligne, " \t\n", mot, MaxMot);				
    		if (mot[0] == 0)            						
          	continue;	
    		if (strcmp(mot[0], "moncd") == 0)					
    		{	if (mot[1] == NULL)								
    			{	dir = getenv("HOME");
    				if (dir == 0)
    				{	dir = "/tmp";
    				}
    			}
    			else if (mot[2] != NULL)						
    			{	fprintf(stderr, "usage: %s [dir]\n", mot[0]);
    				continue;
    			}	
    			else dir = mot[1];								
    			t = chdir(dir);
    			if (t < 0)
    			{	perror(dir);
    			}	
    			continue;
    		}
    		for (cmp = 0; mot[cmp]; cmp++)
    		{	if(mot[cmp] != NULL && strcmp(mot[cmp], tube) == 0)
    			{	mot[cmp] = NULL;
    				mot2[0] = mot[cmp + 1];
    				mot2[1] = NULL;
    				if (pipe(pfd) == -1)
    				{	perror("pipe");
    					continue;
    				}
    				if ((tmp = fork()) < 0)
    				{	perror("fork");
    					continue;
    				}
    				if (tmp == 0)
    				{	close(STDOUT_FILENO);
    					dup(pfd[1]);
    					close(pfd[0]);
    					close(pfd[1]);
    					for(i = 0; dirs[i] != 0; i++)
    					{	snprintf(pathname, sizeof pathname, "%s/%s", dirs[i], mot[0]);
          					execv(pathname, mot);
    					}
    				}
    				else
    				{	close(STDIN_FILENO);
    					dup(pfd[0]);
    					close(pfd[0]);
    					close(pfd[1]);
    					for(i = 0; dirs[i] != 0; i++)
    					{	snprintf(pathname, sizeof pathname, "%s/%s", dirs[i], mot2[0]);
          					execv(pathname, mot2);
    					}
    				}
    			}
    		}
     
    		verif_esperluette();						
    		verif_redirection();						
     
    		tmp = fork();               
        	if (tmp < 0)
    		{	perror("fork");
          		continue;
        	}
     
     
    		if ((tmp != 0) && (test == 1))
    		{	while(wait(0) != tmp);
    			continue;
    		}
    		if((tmp != 0) && (test == 0))
    		{	continue;
    		}
     
     
    		if (fichier_1 == 1)
    		{	out = freopen(path_out, "w+", stdout);
    		}
    		if ((fichier_1 == 1) && (fichier_2 == 1))
    		{	in = freopen(path_in, "r", stdin);
    			out = freopen(path_out, "w+", stdout);
    		}
    		if (fichier_2 == 1)
    		{	in = freopen(path_in, "r", stdin);
    		}
     
     
        	for(i = 0; dirs[i] != 0; i++)
    		{	snprintf(pathname, sizeof pathname, "%s/%s", dirs[i], mot[0]);
          		execv(pathname, mot);
        	}
     
    		fprintf(stderr, "%s: not found\n", mot[0]);
    	    exit(1);
      	}
      	printf("Bye\n");
      	return 0;
    }
    Est-ce que quelqu'un à une idée?
    Merci d'avance.

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Salut

    C'est totalement illisible. Edite ton message pour indenter correctement ton code et le mettre entre balises "CODE" prévues à cet effet.

  3. #3
    Membre émérite
    Avatar de f-k-z
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2006
    Messages
    403
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Mayenne (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juin 2006
    Messages : 403
    Par défaut
    Yopyop,

    Bon, il est tard et l'indentation n'est pas des plus classiques notamment pour l'utilisation des { , mais bon ceci n'est qu'un détail et une question d'habitude :p

    J'ai regardé ton code et il me semble que c'est à toi d'utiliser une fonction pipe().

    Je regarde dans des archives, je dois avoir un truc du genre.

    //edit:
    Issu du man pipe(2). Je te laisse explorer cette piste

    Citation Envoyé par man pipe(2)
    The following program creates a pipe, and then fork(2)s to create a child process. After the fork(2), each process closes the descriptors that it doesn't need for the pipe (see pipe(7)). The parent then writes the string contained in the program's command-line argument to the pipe, and the child reads this string a byte at a time from the pipe and echoes it on standard output.
    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
    #include <sys/wait.h>
    #include <assert.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    int
    main(int argc, char *argv[])
    {
        int pfd[2];
        pid_t cpid;
        char buf;
        assert(argc == 2);
        if (pipe(pfd) == -1) { perror("pipe"); exit(EXIT_FAILURE); }
        cpid = fork();
        if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); }
        if (cpid == 0) {    /* Child reads from pipe */
            close(pfd[1]);          /* Close unused write end */
            while (read(pfd[0], &buf, 1) > 0)
                write(STDOUT_FILENO, &buf, 1);
            write(STDOUT_FILENO, "\n", 1);
            close(pfd[0]);
            _exit(EXIT_SUCCESS);
        } else {            /* Parent writes argv[1] to pipe */
            close(pfd[0]);          /* Close unused read end */
            write(pfd[1], argv[1], strlen(argv[1]));
            close(pfd[1]);          /* Reader will see EOF */
            wait(NULL);             /* Wait for child */
            exit(EXIT_SUCCESS);
        }
    }

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2011
    Messages : 6
    Par défaut
    Merci Yopyop pour ton poste,

    Mais j'avais déjà regardé sous man pipe.

    Seulement voilà le programme affiche le bon résultat, mais ne reste pas dans la boucle. Je ne sais pas trop d'où provient le problème puisqu'il m'affiche correctement le résultat de "ls | wc" seulement après il m'éjecte.

    J'ai un doute et je me demande s'il ne faut pas refaire un 2ième fork() après que l'enfant ait exécute la première commande. (ceci étant dit je l'ai également déjà tenté, mais sans réussir).

    Merci d'avance pour tout proposition.

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Je n'ai lu ton code qu'en diagonale, mais ceci me laisse perplexe :

    Citation Envoyé par Appsolu Voir le message
    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
    int main(int argc, char * argv[])
    {
    []
    				if ((tmp = fork()) < 0)
    				{	perror("fork");
    					continue;
    				}
    				if (tmp == 0)
    				{
    []
    					for(i = 0; dirs[i] != 0; i++)
    					{	snprintf(pathname, sizeof pathname, "%s/%s", dirs[i], mot[0]);
          					execv(pathname, mot);
    					}
    				}
    				else
    				{
    []
    					{	snprintf(pathname, sizeof pathname, "%s/%s", dirs[i], mot2[0]);
          					execv(pathname, mot2);
    					}
    				}
    Tu fais des execv() des deux côtés : dans le processus père et dans son fils.

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2011
    Messages : 6
    Par défaut
    Bonjour Obsidian,

    Merci pour ton poste.

    Oui effectivement je fais des execv(). Est-ce qu'il ne faut pas exécuter une première partie de la commande et puis la deuxième?

    Dans le cas de "ls | wc" je pensait exécuter ls puis envoyer le résultat à wc?

    Comment procéder alors? je suis désespère, celà fas plus d'une semaine que je passe dessus, sans résultat.

    Merci à vous.

  7. #7
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Ce n'est pas le fait de faire execv() qui pose problème, c'est le fait de le faire des deux côtés.

    La famille des exec() remplace l'image du processus en cours par celle qu'il va charger depuis ton exécutable. C'est précisément pour cela que l'on fait un fork() avant : parce que le processus fils va devenir celui qu'on va lancer.

    Si tu fais execv() depuis le père, tu écrases ton mini-shell.

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2011
    Messages : 6
    Par défaut
    Salut Obsidian

    Merci pour ton commentaire, je vais revoir mon script. Je te tiens au courant de l'évolution de mon problème.

    En attentant encore merci de m'aider, c'est pas toujours évident quand ont est seul et débutant. Je commence a regagner espoir

    A+

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2011
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Luxembourg

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2011
    Messages : 6
    Par défaut
    Bon, c'est pas gagné.

    J'ai suivi ton commentaire Obsidian et je n'arrête pas de tourner le tout. J'ai simplifié ma fonction de façon a vérifier si j'arrive au moins à implémenter le code correcte pour les pipes mais malheureusement sans aboutir.

    Voilà ou j'en suis:
    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
    int main(int argc, char * argv[])
    {  	decouper(getenv("PATH"), ":", dirs, MaxDirs);			
      	for(printf(PROMPT); fgets(ligne, sizeof ligne, stdin) != 0; printf(PROMPT))
    	{	decouper(ligne, " \t\n", mot, MaxMot);				
    		if (mot[0] == 0)            						
          	continue;	
    		int pfd[2];
    		char buf[1024];
    		pipe(pfd);
    		int pid;
    		pid = fork();
    		if (pid != 0)
    		{	close(pfd[1]);
    			while (wait(0)!= pid);
    			read(pfd[0], buf, sizeof(buf));
    			printf("read %s\n", buf);
    			continue;
    		}
    		else if (pid == 0)
    		{	close(pfd[0]);
    			close(1);
    			dup(pfd[1]);
    			close(pfd[1]);
    			for(i = 0; dirs[i] != 0; i++)
    			{	snprintf(pathname, sizeof pathname, "%s/%s", dirs[i], mot[0]);
          			execv(pathname, mot);
    			}
    		}
     
    		fprintf(stderr, "%s: not found\n", mot[0]);
    	    exit(1);
      	}
      	printf("Bye\n");
      	return 0;
    }
    Et voilà le message d'erreur que j'obtiens:

    ? ls wc
    ls: ne peut accéder wc: Aucun fichier ou dossier de ce type
    read t
    ?

    Du moins maintenant je reste dans la boucle du mini shell.

    Pour résumer je ne comprend vraiment pas ce qui bloque, si quelqu'un à une idée resp. proposition, je suis preneur.

    Merci à vous.

Discussions similaires

  1. Creation d'un shell probleme avec execve
    Par Mouch2 dans le forum Débuter
    Réponses: 3
    Dernier message: 07/01/2011, 17h37
  2. script shell : probleme avec sed et awk
    Par salseropom dans le forum Shell et commandes GNU
    Réponses: 3
    Dernier message: 05/06/2007, 11h57
  3. [VC++] probleme avec le Pipe Named
    Par ksoft dans le forum Visual C++
    Réponses: 2
    Dernier message: 21/07/2006, 18h34
  4. Problème avec mon script en Shell
    Par G.D.O dans le forum Linux
    Réponses: 8
    Dernier message: 05/07/2006, 16h40
  5. [VBscript] probleme avec shell.exec
    Par eown dans le forum Windows
    Réponses: 1
    Dernier message: 23/04/2006, 09h24

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