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

Linux Discussion :

Créer un shell avec un pipe


Sujet :

Linux

  1. #1
    Membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Avril 2014
    Messages
    123
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Avril 2014
    Messages : 123
    Points : 66
    Points
    66
    Par défaut Créer un shell avec un pipe
    Bonjour, ça fait plusieurs jours que je suis sur la création d'un shell qui gère certaines commandes internes, les commandes en tâches de fond (elles commencent par "tf"), et là je bloque sur la création d'un pipe. Tout marche sauf le pipe. Je vous préviens le code est un peu "sale", on peut surement l'améliorer et l'optimiser, je ne comprends pas bien les commandes pipe() et dup2(), est-ce que quelqu'un pourrait me les expliquer pour le pipe ? Dans quel ordre faut-il les mettre ? Et quelles sont mes erreurs dans mon code ? Merci beaucoup !

    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
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
     
    #include <stdio.h>
    #include <unistd.h>
    #include "ligne_commande.h"
    #include <sys/types.h> 
    #include <sys/wait.h> 
    #include <string.h>
    #include <stdlib.h>
    #include <assert.h>
     
    int commandes_internes (char** cmd,int cpt );
    int split(char** cmd, int cpt_str, char* commande1[],char* commande2[]);
    int verif_pipe(char** cmd, int cpt_str);
     
    int main()
    {
    	char** commande;
    	char** commande1;
     
    	char** commande2;
     
    	int status;
    	int nb,cpt,i;
    	int pipefd[2];
    	int cpt_str,j;
    	int nb_split1=0;
    	cpt=0;
    	commande1 = malloc(sizeof(char*)*20);
    	for(i=0;i<20; i++) 
    	  commande1[i] = malloc(sizeof(char)*10); 
    	commande2 = malloc(sizeof(char*)*20);
    	for(i=0;i<20; i++) 
    	  commande2[i] = malloc(sizeof(char)*10);
    	setenv("INVITE", "\n> ", 1);
    	do
    	{
    		printf("%s", getenv("INVITE"));
    		fflush(stdout);
    		commande=lis_ligne(&cpt_str);
    		if(commande==NULL) return 0;
    		if(commande[0]==NULL) continue;
     
    		if( !commandes_internes(commande,cpt) ) //commande externe
    		{			
    			int pid=fork();
    			if(pid==0)
    			{
    				if(strcmp(commande[0],"tf")!=0 && !verif_pipe(commande, cpt_str)) {nb=execvp(commande[0],commande);}
    				else if (verif_pipe(commande, cpt_str))
    				{
    					while(strcmp(commande[nb_split1],"|")!=0)
    					{
    						strcpy(commande1[nb_split1],commande[nb_split1]);
    						nb_split1=nb_split1+1;
    					}
    					commande1[nb_split1+1]=NULL;
    					for(j=nb_split1+1;j<cpt_str;j++)
    					{
    						strcpy(commande2[j],commande[j]);
    						j++;
    					}
    					commande2[j+1]=NULL;
     
    					nb=pipe(pipefd);
    					if(nb==-1)
    						{
    							perror("Erreur de l'appel systeme pipe");
    							return(-1);
    						}
    					int pid3=fork();
    					if(pid3==0)
    					{
    						dup2(pipefd[1], 1);
    						close(pipefd[0]);
    						close (pipefd[1]);
    						nb=execvp(commande1[0],commande1);
    						if(nb==-1) printf("Cette commande n'existe pas.\n");fflush(stdout);
    					}
    					else if (pid3 > 0)
    					{
    						/* Parent */
    						dup2(pipefd[0],0);
    						close(pipefd[0]);
    						close(pipefd[1]);
    						waitpid(pid3, &status,0);
    					}
    					else if (pid3==-1)
    					{
    						perror("Erreur de l'appel systeme fork");
    						return(-1);
    					}
    					int pid4=fork();
    					if(pid4==0)
    					{
    						nb=execvp(commande2[0],commande2);
    						if(nb==-1) printf("Cette commande n'existe pas.\n");fflush(stdout);
    					}
    					else if (pid4 > 0)
    					{
    						/* Parent */
    						waitpid(pid4, &status,0);
    					}
    					else if (pid4==-1)
    					{
    						perror("Erreur de l'appel systeme fork");
    						return(-1);
    					}
    				}
    				else 
    				{				
    					cpt++;				
    					int pid2=fork();
    					if(pid2==0)
    					{					
    						nb=execvp(commande[1],commande+1);
    					}
    					else if (pid2==-1)
    					{
    						perror("Erreur de l'appel systeme fork");
    						return(-1);
    					}
    					else
    					{					
    						waitpid(pid2,&status,0);
    						printf("Le processus en tache de fond numero %d est termine.",pid2);
    					}
    				}
    				if(nb==-1) printf("Cette commande n'existe pas.\n");fflush(stdout);
    			}
    			else if (pid==-1)
    			{
    				perror("Erreur de l'appel systeme fork");
    				return(-1);
    			}
    			else
    			{
    				if(strcmp(commande[0],"tf")!=0)
    					waitpid(pid,&status,0);
    			}
    		}
    	} while (fin_de_fichier(commande)==0 || ligne_vide(commande)==1);
    return 0;
    }
     
    int commandes_internes (char** cmd,int cpt ){
     
    	char* droite;
    	int nb,i,status;	
    	if( strcmp(cmd[0],"exit") == 0 )  //strcmp compare 2 chaînes de caractère et renvoie 0 si elles sont identiques
    	{
    		printf("fin du programme\n");
    		for(i=0;i<cpt;i++)
    		{
    			waitpid(-1,&status,0);	
    		}
    		exit(0); //fin du programme
    	}
     
     
    	if( strcmp(cmd[0],"cd")==0 ) 
    	{
    		if(cmd[1])
    		{
    			nb=chdir(cmd[1]);
    			if(nb==-1) perror("Erreur de la commande chdir.");
    		}
    		else printf("Syntaxe : cd argument");
    		return 1;
    	}
     
    	if( strcmp(cmd[0],"export")==0 )
    	{	
    		if(cmd[1])
    		{
    		droite=separe_egal(cmd[1]);
    		if(droite==NULL) printf("La commande export n'a pas de signe egal.");
    		nb=setenv(cmd[1], droite, 1);
    		if(nb==-1) perror("Il n'y a plus de place pour cette variable d'environnement.");
    		}
    		else
    			printf("Syntaxe : export arg1=arg2");
    		return 1;
    	}
     
    	return 0;
    }
     
    int verif_pipe(char** cmd, int cpt_str)
    {
    	int i;
    	for(i=0;i<cpt_str;i++)
    	{
    		if(strcmp(cmd[i],"|")==0) return 1;
    	}
    	return 0;
    }

  2. #2
    Membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Avril 2014
    Messages
    123
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Avril 2014
    Messages : 123
    Points : 66
    Points
    66
    Par défaut
    Finalement j'ai pu résoudre mes problèmes, j'ai rajouté des commentaires, mais est-ce que vous pourriez m'aider à améliorer et optimiser mon code, sachant que pour l'instant je ne gère que le cas où il y a un seul pipe ?

    shell3.c :
    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
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
     
    #include <stdio.h>
    #include <unistd.h>
    #include "ligne_commande.h"
    #include <sys/types.h> 
    #include <sys/wait.h> 
    #include <string.h>
    #include <stdlib.h>
    #include <assert.h>
     
    int commandes_internes (char** cmd,int cpt );	// execute exit,cd,export->modif des variables d'environnement
    int verif_pipe(char** cmd, int cpt_str);	//verifie si la commande contient un pipe
     
    int main()
    {
    	char** commande;	//tableau de strings contenant la commande totale
    	char** commande1=malloc(512);	//tableau de strings contenant la 1er commande dans le cas d'un pipe
    	char** commande2=malloc(512);	//tableau de strings contenant la 2e commande dans le cas d'un pipe
    	int status;		//statut de la commande waitpid
    	int nb,cpt,j;	//nb -> resultat d'un appel systeme cpt -> nb de processus lances en tâche de fond j -> cpteur pour la commande2
    	int pipefd[2];	//tableau des file descriptors du pipe
    	int cpt_str;	//nb de strings dans une commande
    	int nb_split1=0;	//nb de strings dans la premiere commande
    	cpt=0;
    	setenv("INVITE", "\n> ", 1);	//initialisation de l'invite de commandes a '>'
    	do
    	{
    		printf("%s", getenv("INVITE"));
    		fflush(stdout);
    		commande=lis_ligne(&cpt_str);	//la fonction lis_ligne retourne un tableau de strings et le nombre de strings de la commande va dans cpt_str
    		if(commande==NULL) return 0;	//si la fin de fichier est rencontree le programme s'arrete
    		if(commande[0]==NULL) continue;		//si on appuie directement sur entree
     
    		if( !commandes_internes(commande,cpt) ) //commande externe
    		{			
    			int pid=fork();
    			if(pid==0)	//fils
    			{
    				if(strcmp(commande[0],"tf")!=0 && !verif_pipe(commande, cpt_str)) nb=execvp(commande[0],commande); // si la commande ne commence pas par tf(tâche defond) et s'il n'y a pas de pipe on exécute directement la commande
    				else if (verif_pipe(commande, cpt_str))		//s'il y a un pipe
    				{
    					while(strcmp(commande[nb_split1],"|")!=0)	//copie de la premiere commande dans commande1
    					{
    						*(commande1+nb_split1)= *(commande+nb_split1);
    						nb_split1=nb_split1+1;
    					}
    					*(commande1+nb_split1)=NULL;	//la commande doit se terminer par NULL pour etre executee par execvp
    					for(j=nb_split1+1;j<cpt_str;j++)	//copie de la deuxieme commande dans commande2
    					{
    						*(commande2+j-nb_split1-1)= *(commande+j);
    					}
    					 *(commande2+j-nb_split1-1)=NULL;
     
    					int pid3=fork();
    					if(pid3==0)		//petit-fils
    					{
    						nb=pipe(pipefd);	//creation du pipe
    						if(nb==-1)
    						{
    							perror("Erreur de l'appel systeme pipe");
    							return(-1);
    						}
    						int pid4=fork();
    						if(pid4 < 0)
    						{
    							perror("Création de fork échouée");
    							return(-1);
    						}
    						//Le processus fils s'occupe de la première commande
    						//et envoie le résultat au père.
    						else if (pid4 == 0) {
    							close(pipefd[0]); //fermeture du coté read du pipe
    							dup2(pipefd[1],1);	//redirection de la sortie standard vers le cote ecriture du pipe
    							nb=execvp(commande1[0],commande1);
    							if(nb==-1) printf("Cette commande n'existe pas.\n");fflush(stdout);
    						}
    						//Le père réceptionne le résultat du fils et traite la seconde commande.
    						else
    						{
    							close(pipefd[1]);	//fermeture du coté ecriture du pipe
    							dup2(pipefd[0],0);	//redirection de l'entree standard vers le cote lecture du pipe
     
    							nb=execvp(commande2[0],commande2);
    							if(nb==-1) printf("Cette commande n'existe pas.\n");fflush(stdout);
    						}
    					}
    					else if (pid3 > 0)	//pere attend
    					{
    						waitpid(pid3, &status,0);
    					}
    					else if (pid3==-1)
    					{
    						perror("Erreur de l'appel systeme fork");
    						return(-1);
    					}
    				}
    				else 
    				{				
    					cpt++;		//cpt s'incremente si commande en tâche de fond		
    					int pid2=fork();
    					if(pid2==0)		//creation d'un 2e fork pour monitorer les processus en tâches de fond
    					{					
    						nb=execvp(commande[1],commande+1);
    					}
    					else if (pid2==-1)
    					{
    						perror("Erreur de l'appel systeme fork");
    						return(-1);
    					}
    					else
    					{					
    						waitpid(pid2,&status,0);
    						printf("Le processus en tache de fond numero %d est termine.",pid2);
    					}
    				}
    				if(nb==-1) printf("Cette commande n'existe pas.\n");fflush(stdout);
    			}
    			else if (pid==-1)
    			{
    				perror("Erreur de l'appel systeme fork");
    				return(-1);
    			}
    			else
    			{
    				if(strcmp(commande[0],"tf")!=0) // le pere n'attend que s'il n'y a pas de commande en tâche de fond
    					waitpid(pid,&status,0);
    			}
    		}
    	} while (fin_de_fichier(commande)==0 || ligne_vide(commande)==1);
    return 0;
    }
     
    int commandes_internes (char** cmd,int cpt ){
     
    	char* droite;
    	int nb,i,status;	
    	if( strcmp(cmd[0],"exit") == 0 )  //strcmp compare 2 chaînes de caractère et renvoie 0 si elles sont identiques
    	{
    		printf("fin du programme\n");
    		for(i=0;i<cpt;i++)	//lorsqu'on entre exit le pere attend tous les fils restants pour eviter la creation de zombies
    		{
    			waitpid(-1,&status,0);	
    		}
    		exit(0); //fin du programme
    	}
     
     
    	if( strcmp(cmd[0],"cd")==0 ) 
    	{
    		if(cmd[1])
    		{
    			nb=chdir(cmd[1]);
    			if(nb==-1) perror("Erreur de la commande chdir.");
    		}
    		else printf("Syntaxe : cd argument");
    		return 1;
    	}
     
    	if( strcmp(cmd[0],"export")==0 )
    	{	
    		if(cmd[1])
    		{
    		droite=separe_egal(cmd[1]);
    		if(droite==NULL) printf("La commande export n'a pas de signe egal.");
    		nb=setenv(cmd[1], droite, 1);
    		if(nb==-1) perror("Il n'y a plus de place pour cette variable d'environnement.");
    		}
    		else
    			printf("Syntaxe : export arg1=arg2");
    		return 1;
    	}
     
    	return 0;
    }
     
    int verif_pipe(char** cmd, int cpt_str)		//retourne 1 s'il y a un pipe
    {
    	int i;
    	for(i=0;i<cpt_str;i++)
    	{
    		if(strcmp(cmd[i],"|")==0) return 1;
    	}
    	return 0;
    }
    ligne_commande.h :
    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
     
    #ifndef _LIGNE_COMMANDE_V2_H
    #define _LIGNE_COMMANDE_V2_H
     
    /**
     * Cette fonction lit sur l'entrée standard une ligne de texte,
     * la découpe selon les espaces, et retourne un tableau de char*
     * du type attendu par execv et execvp.
     *
     * Si la fin de fichier est rencontrée, cette fonction retourne NULL.
     *
     * Voir aussi les fonctions fin_de_fichier et ligne_vide.
     */
     
    char** lis_ligne(int* cpt);
     
    /**
     * Cette fonction prend en paramètre le tableau de char* retourné par lis_ligne
     * et retourne vrai si et seulement si lis_ligne a rencontré la fin de fichier.
     * (c.à.d. si ligne est NULL)
     */
    int fin_de_fichier(char** ligne);
     
    /**
     * Cette fonction prend en paramètre le tableau de char* retourné par lis_ligne
     * et retourne vrai si la ligne lue était vide.
     * Pré-condition: on n'est pas en fin de fichier, ligne != NULL
     */
    int ligne_vide(char** ligne);
     
     
    /**
     * Cette procédure coupe une chaîne de caractères en deux à l'endroit du signe
     * égal, de sorte qu'après son exécutuion:
     *  - la chaîne passée en paramètre ne contient plus que sa partie gauche,
     *  - le pointeur retourné pointe vers la partie droite.
     *
     * Si la chaîne passée en paramètre ne contient pas le signe égal, la chaîne
     * n'est pas modifiée, et la fonction retourne NULL.
     */
    char* separe_egal(char* str);
     
     
    #endif
    ligne_commande.c :
    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
     
    /**
     * Pour la documentation, voir ligne_commande_v2.h .
     */
     
    #include "ligne_commande.h"
     
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
     
    #define LBUF 1024
    #define LLIGNE 256
    static char buf[LBUF];
    static char* ligne[LLIGNE];
     
    char** lis_ligne(int* cpt)
    {
        int i = 0;
        int s;
        do
        {
            s = read(0, buf+i, 1);
            i += s;
        } while (i < LBUF-1  &&  s > 0  &&  buf[i-1] != '\n');
        if (s < 0) perror("erreur de lecture dans lis_ligne");
        if (i == 0) return NULL;
     
        // découpage
        char* tok;
        buf[i] = '\0';
        *cpt = 0;
        ligne[0] = strtok_r(buf, " \t\n\r", &tok);
        while (ligne[*cpt] && *cpt < LLIGNE-1)
        {
            *cpt += 1;
            ligne[*cpt] = strtok_r(NULL, " \t\n\r", &tok);
        }
        if (*cpt == LLIGNE-2) ligne[LLIGNE-1] = NULL;
        return ligne;
    }
     
    int fin_de_fichier(char** ligne)
    {
        return ligne == NULL;
    }
     
    int ligne_vide(char** ligne)
    {
        return ligne[0] == NULL;
    }
     
    char* separe_egal(char* str)
    {
      char* p = str;
      while (*p) {
        if (*p == '=') {
          *p = '\0';
          return p+1;
        }
        p++;
      }
      return NULL;
    }
    Makefile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    shell3: shell3.c ligne_commande.c ligne_commande.h
    	gcc -Wall -Werror -o shell3 shell3.c ligne_commande.c
     
    clean :
    	rm -f shell3
    Merci !!

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 10/06/2014, 14h21
  2. Créer ou modifier un shell avec interface python et le lancer
    Par jameson dans le forum Général Python
    Réponses: 11
    Dernier message: 26/08/2008, 09h59
  3. Réponses: 3
    Dernier message: 21/09/2003, 15h52
  4. créer un noeuds avec des paramétres
    Par Toxine77 dans le forum XMLRAD
    Réponses: 5
    Dernier message: 21/01/2003, 16h11
  5. [CR] Est il possible de créer des univers avec Seagate Info?
    Par Frank dans le forum SAP Crystal Reports
    Réponses: 1
    Dernier message: 27/06/2002, 15h22

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