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 :

Executer une commande linux dans son propre shell


Sujet :

C

  1. #1
    Membre régulier

    Homme Profil pro
    Étudiant
    Inscrit en
    mai 2014
    Messages
    55
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mai 2014
    Messages : 55
    Points : 114
    Points
    114
    Par défaut Executer une commande linux dans son propre shell
    Bonjour,
    j'écris un code en C qui a pour but de simuler le fonctionnement d'un terminal linux. Cependant je suis confronté ànquelques soucis:
    La commande ls ne marche pas
    si j'utilise des commandes comme
    touch
    ou
    mv
    le nom du fichier sortant est entouré entre deux
    '
    et des caractères sont rajoutés voir image ci-dessous.
    Voici le 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
    103
    104
    105
    106
    107
    108
    109
    110
    111
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <errno.h>
     
    #define CHAR_MAX_LENGTH 1000
    #define INVITE_SYMBOL "shell>"
     
    int Ndelimiteur(char *string_in){
    	int i, l = 0, n = 0, len = strlen(string_in) + 1;
    	char delimiter = ' ';
    	for(i = 0; i < len; i++){
    		if( !( (string_in[i] != '\0') && (string_in[i] != delimiter)) ){
    			n++;
    		}
    	}
    	return n;
    }
     
     
    void delimiteur(char *string_in, char *string_out, int nbr)
    {
     
        char c = ' ';
     
        int i, l = 0, n = 0, len = strlen(string_in) + 1;
     
        for (i = 0; i < len; i++) {
     
    	if ((string_in[i] != '\0') && (string_in[i] != c)) {
     
    	    string_out[l] = string_in[i];
     
    	    l++;
     
    	} else {
     
    	    if (l > 0) {
     
    		string_out[l] = 0;
     
    		l = 0;
     
    		if (n == nbr)
    		    return;
     
    		n++;
    	    }
     
    	}
     
        }
     
    }
     
     
    void quitt(){
    	fprintf(stdout,"========== CLOSING COURSE ==========\n");
    	fprintf(stdout,"3\n"); sleep(1);
    	fprintf(stdout,"2\n"); sleep(1);
    	fprintf(stdout,"1\n"); sleep(1);
    }
     
    int main(int argc, char *argv[]){
     
    	char exiting[5] = { 0 };
    	int i, n;
    	char buff_in[CHAR_MAX_LENGTH] = {0};
     
    	/* COMMAND ELEMENT */
    	char user_string[CHAR_MAX_LENGTH] = {0};
    	//char command[50] = {0};
     
    	while(1){
    		write(STDOUT_FILENO, INVITE_SYMBOL, sizeof(INVITE_SYMBOL));
    		read(STDIN_FILENO,buff_in, sizeof(buff_in));
     
    		// QUIT THE PROGRAMM IF USER's STRING IS quit OR exit
    		strncpy(exiting, buff_in, 4); //copy 4th first char
    		if( (strcmp(exiting, "exit") == 0) || (strcmp(exiting, "quit") == 0) ){
    			if(atexit(quitt) == -1){
    				perror("Error while closing programm");
    			}
    			break;
    		}
     
    		//fprintf(stdout, "%s",buff_in);
     
    		/* GET COMMAND */
     
    		n = Ndelimiteur(buff_in);
    		char *param[n+1];
     
    		for(i = 0; i < n; i++){
    			/* 
    			on place successivement dans user_string les chaines
    			de caractères de buff_in dès que nous rencontrons un caractère espace
    			*/
    			delimiteur(buff_in, user_string, i);  
    			//fprintf(stdout, "user string: %s", user_string);	
    			param[i] = strdup(user_string);
    		}
     
    		param[n] = NULL;
    		execvp(param[0], param);	
    		fprintf(stderr, "Error %d\n", errno);
    	}
    	return EXIT_SUCCESS;
    }
    et voici en image la sortie
    Nom : test_LI.jpg
Affichages : 206
Taille : 1,68 Mo
    Merci

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    9 809
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 9 809
    Points : 26 750
    Points
    26 750
    Billets dans le blog
    1
    Par défaut
    Bonjour

    J'ai pas tout regardé en détail (surtout pour le coup des quotes rajoutées au nom du fichier) mais j'ai trouvé le souci des commandes de bases (ex ls, touch, etc). C'est à cause de ta saisie read(STDIN_FILENO,buff_in, sizeof(buff_in)) qui stocke dans "buff_in" le caractère '\n' représentant le "return" quand tu valides ta ligne. Ce '\n' fout ensuite la zone dans le execvp().
    Rajoute juste en dessous char *pt; if ((pt=strchr(buff_in, '\n')) != NULL) *pt='\0';.

    Une erreur qui n'a pas d'influence dans ce code mais pourrait en avoir plus tard (suite à évolution) : on n'utilise jamais sizeof() pour un tableau. Parce que tant que c'est un tableau ça marche, mais si ce tableau devient un pointeur, là ça marche plus.
    Exemple

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main() {
    	char buff_in[CHAR_MAX_LENGTH];
    	read(STDIN_FILENO,buff_in, sizeof(buff_in));
    }

    Ok, ça marche. Mais demain tu décides (pour optimisation ou autre) de déplacer la saisie...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int main() {
    	char buff_in[CHAR_MAX_LENGTH];
    	saisie(buff_in);
    }
     
    void saisie(char *buff_in) {
    	read(STDIN_FILENO,buff_in, sizeof(buff_in));
    }
    Tu as pourtant bien fait les choses (déplacé les instructions qui vont bien dans la sous-fonction)... mais malgré ça ça ne marche plus parce que sizeof(pointeur) n'est pas la même chose que sizeof(tableau).

    Ton tableau a été défini par rapport à une constante, autant l'utiliser...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main() {
    	char buff_in[CHAR_MAX_LENGTH];
    	read(STDIN_FILENO,buff_in, CHAR_MAX_LENGTH);
    }
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  3. #3
    Membre régulier

    Homme Profil pro
    Étudiant
    Inscrit en
    mai 2014
    Messages
    55
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mai 2014
    Messages : 55
    Points : 114
    Points
    114
    Par défaut
    Merci @Sve@r ta réponse m'a permis de résoudre le problème d’exécution.
    Celà dit j'arrive pas à voir comment faire qu'elles(les commandes) s’exécutent en arrière plan après l'ajout du
    &

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    9 809
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 9 809
    Points : 26 750
    Points
    26 750
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Taserface Voir le message
    Merci @Sve@r ta réponse m'a permis de résoudre le problème d’exécution.
    D'autant plus que les quotes simples ne venaient pas de ton programme mais du message d'erreur de "ls" quand il ne trouve pas le fichier. Et il ne trouvait pas le fichier là encore à cause du '\n'.

    Citation Envoyé par Taserface Voir le message
    Celà dit j'arrive pas à voir comment faire qu'elles(les commandes) s’exécutent en arrière plan après l'ajout du
    Héhé, parce que tu n'as pas programmé ton shell dans les règles de l'art.

    Quand le shell (le vrai) doit exécuter une commande, il commence par générer un fils (fork()) et c'est le fils qui se charge d'exécuter la commande (exec()) pendant que le père attend (wait()) la fin du fils.
    A priori ça semble identique (voire même idiot) sauf que justement non c'est pas idiot car c'est là, quand la commande contient un "&", le père n'attend alors plus la fin du fils et rend la main pour une nouvelle commande.

    Et toi, ben t'as pas généré de fils donc c'est le père qui attend la fin de la commande et ça tu peux pas le shunter.
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  5. #5
    Membre régulier

    Homme Profil pro
    Étudiant
    Inscrit en
    mai 2014
    Messages
    55
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mai 2014
    Messages : 55
    Points : 114
    Points
    114
    Par défaut
    j'avais déjà introduit la notion de processus comme tu peux le voir sur l'image ci-dessous.
    J'explique: quand je lance mon shell(qui est un processus) et que j'execute une commande avec un
    &
    à la fin je crée un autre sous processus pour executer la commande et retourner au processus parent qui est le shell.
    Nom : proc.PNG
Affichages : 191
Taille : 37,6 Ko
    Le code ne diffère en rien au précedent excepté l'ajout de création de processus

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    9 809
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 9 809
    Points : 26 750
    Points
    26 750
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Taserface Voir le message
    J'explique: quand je lance mon shell(qui est un processus) et que j'execute une commande avec un & à la fin je crée un autre sous processus pour executer la commande et retourner au processus parent qui est le shell.
    J'en conclus que quand la commande n'est pas terminée par "&" tu la fais exécuter par le père ? C'est pas bon. Parce que exec() remplace le processus en cours par celui de la commande exécutée. Donc le père (le shell) disparait au profit de la commande. C'est dommage un shell qui ne permet d'exécuter qu'une seule commande car ensuite il n'existe plus.
    C'est d'ailleurs peut-être pour ça que ton shell ne boucle pas. Il exécute la commande demandée puis il quitte. Or un vrai shell boucle en mode infini jusqu'à exit ou ctrl-d...
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  7. #7
    Membre régulier

    Homme Profil pro
    Étudiant
    Inscrit en
    mai 2014
    Messages
    55
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mai 2014
    Messages : 55
    Points : 114
    Points
    114
    Par défaut
    Mon shell boucle bien et tant que j'entre pas explicitement exit ou quit mon shell s'execute et je peux executer des commandes
    J'en conclus que quand la commande n'est pas terminée par "&" tu la fais exécuter par le père ?
    non il est éxecuté par le fils voir code code de la partie Cependant ce processus fils crée aussi un sous processus si la commande se termine par un & executant celui-ci en arrière plan du processus fils pid_first_son qui devient son père du moins c'est cette conception que j'ai essayé d'implementer.
    Sinon si on enlève tout le bloc et que j'entre la commande top j'ai bien une execution et quand j'appuie sur q je reviens sur mon shell et non le terminal du système

  8. #8
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    9 809
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 9 809
    Points : 26 750
    Points
    26 750
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Taserface Voir le message
    Cependant ce processus fils crée aussi un sous processus si la commande se termine par un & executant celui-ci en arrière plan du processus fils pid_first_son qui devient son père du moins c'est cette conception que j'ai essayé d'implementer.
    Donc comme je t'ai dit, c'est pas comme ça qu'il faut implémenter. Le fils n'a jamais besoin de créer lui-même un fils. C'est juste le père qui ira choisir entre attendre (pas de "&") ou ne pas attendre ("&" présent) la fin du fils qui exécute la commande.

    Ceci dit tu as aussi le droit de tenter avec ta méthode. C'est un peu plus compliqué mais ça devrait marcher. Mais si je reprends ta seconde question "Celà dit j'arrive pas à voir comment faire qu'elles(les commandes) s’exécutent en arrière plan après l'ajout du &" je ne vois pas ce qui te gêne. Tu sais gérer un fork() et les processus donc il n'y a rien qui devrait t'embêter.
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  9. #9
    Membre régulier

    Homme Profil pro
    Étudiant
    Inscrit en
    mai 2014
    Messages
    55
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mai 2014
    Messages : 55
    Points : 114
    Points
    114
    Par défaut
    Ce genre de code ? (ça ne marche pas)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    if(pid_son ==0){
      execvp(param[0], param);
    }else{
      if( strcmp(param[n-1, "&") !=0 ){
        waitpid(pid_son, NULL, 0);
      }
      //ici un wait(NULL) ? ou quoi ?
    }

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    9 809
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : février 2006
    Messages : 9 809
    Points : 26 750
    Points
    26 750
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Taserface Voir le message
    Ce genre de code ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    if(pid_son ==0){
      execvp(param[0], param);
    }else{
      if( strcmp(param[n-1, "&") !=0 ){
        waitpid(pid_son, NULL, 0);
      }
      //ici un wait(NULL) ? ou quoi ?
    }
    C'est ça (ne pas oublier le crochet fermant à "param[n-1]" mais ça reste l'idée)

    Citation Envoyé par Taserface Voir le message
    (ça ne marche pas)
    Ah ben faut investiguer un peu. Pour ton tout premier code j'ai pas trouvé en flairant les odeurs dans le vent. J'ai mis des printf() pour voir ce qui se passait. En fait bon j'avais une petite idée donc j'ai mis juste un printf() pour vérifier mais la méthode ne change pas. Es-tu sûr que que strcmp(param[n-1], "&") est différent de 0 ???
    Et puis si tu lis les règles du forum tu verras qu'on a horreur du bête "ça marche pas". Qu'est-ce qui marche pas ? Le père attend ? Il n'attend pas ? Ca plante ?
    Quant à wait(NULL) non. Parce que là, ça attend le premier fils. Donc si on lance 3 commandes en arrière plan et une 4° en normal, on ne sait pas laquelle on attend. En mode debug oui car ça peut permettre de vérifier si le souci vient de waitpid() (moi je n'y crois pas) mais dans un code finalisé faut le changer.
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

Discussions similaires

  1. Comment faire une redirection et un tube dans son propre shell?
    Par AntoineCompagnie dans le forum Linux
    Réponses: 1
    Dernier message: 18/12/2015, 17h10
  2. lancer une commande linux dans un script perl
    Par hammag dans le forum Langage
    Réponses: 1
    Dernier message: 21/11/2007, 17h18
  3. [Système] executer une commande linux
    Par kirbs dans le forum Langage
    Réponses: 7
    Dernier message: 08/12/2005, 10h40
  4. Executer une commande linux distante
    Par g-rom3 dans le forum Linux
    Réponses: 11
    Dernier message: 06/11/2005, 20h33
  5. Réponses: 2
    Dernier message: 24/06/2003, 21h31

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