TP Intéraction entre le C et le Shell

Filière Eurecom

Philippe Dax


Sommaire


Introduction

Le but de ce TP est d'utiliser les facilités offertes par l'interpréteur Shell et les commandes accessibles à partir du Shell à travers des programmes écrits en langage C.

Un programme C interagit avec le Shell par 2 moyens, interaction avec la ligne de commande et interaction pendant le traitement propre.

  1. Un programme C récupère les informations tapées sur la ligne commande du Shell par l'intermédiaire des variables prédéfinies argc et argv. Ces variables doivent être déclarées en argument de la fonction main() qui sera le point d'entrée initial du programme C. L'analyse syntaxique de ligne de commande étant alors à la charge du programme C.
  2. Au niveau de l'intéraction des données entre le programme C et le Shell il existe 2 fonctions de la bibliothèque C standard qui permettent d'interagir avec les commandes du Shell, à savoir system() et popen().

argc, argv

Les 2 arguments argc et argv sont transmis du Shell à la fonction main() du programme utilisateur. La syntaxe de la fonction main() est la suivante: main(int argc, char ** argv) Le schéma ci-dessous illustre le tableau argv: $ commande argument1 argument2 argument3 ^ ^ ^ ^ | | | | ------------ | | | | argv -->| argv[0] |------- | | | |----------| | | | | argv[1] |---------------- | | |----------| | | | argv[2] |-------------------------- | |----------| | | argv[3] |------------------------------------ |----------| | null | ------------

Fonction getopt()

La grande majorité des commandes Unix utilisent la convention -lettre pour désigner une option ( -a, -b, -c,... ). La fonction getopt() s'appuit sur cette convention pour faciliter la phase de l'analyse syntaxique de la ligne de commande.
La syntaxe de la fonction getopt est la suivante: int getopt(int argc, char ** argv, char * optstring) extern char *optarg; extern int optind, opterr; getopt() retourne la lettre de l'option courante de la ligne de commande qui correspond à l'une des lettres d'option présente dans la chaîne optstring. La chaîne de référence optstring doit contenir l'ensemble des lettres d'option possibles.
Si une lettre d'option est suivie d'un caractère ':', cette option annonce un ou plusieurs arguments séparés par un espace. La variable optarg est alors pré-initialisée pour pointer sur le début de l'argument de l'option.
optind est l'index de la chaîne courante, il est compris entre 0 et argc.

Exemple:

main (int argc, char **argv) { int c; extern char *optarg; extern int optind; extern int opterr; extern int optopt; int aflg = 0; int bflg = 0; int errflg = 0; char *ofile = NULL; opterr=0; while ((c = getopt(argc, argv, "abo:")) != EOF) { switch (c) { case 'a': if (bflg) errflg++; else aflg++; break; case 'b': if (aflg) errflg++; else bflg++; break; case 'o': ofile = optarg; (void)printf("ofile = %s\n", ofile); break; case '?': printf("OPTOPT= %c\n",optopt); errflg++; } } if (errflg) { (void)fprintf(stderr, "usage: cmd [-a|-b] [-o ] files...\n"); exit (2); } printf("Autres arguments:\n"); for ( ; optind < argc; optind++) (void)printf("%s\n", argv[optind]); }

Fonction system()

La syntaxe de la fonction system() est la suivante: system(char *commande) commande est une chaîne de caractères qui contient le nom d'une commande Unix et éventuellement ses paramètres séparés par un ou plusieurs caractères blanc (espace ou tabulation).
Exemple: system("grep \":ppp-stud\" /infres/admin/ppp/ppp.map"); Cet appel de fonction permet de lister toutes les lignes du fichier /infres/admin/ppp/ppp.map dans lequel apparait les sous-chaînes de caractères :ppp-stud:. Cette sous-chaîne est quotée à l'aide du caractère '"'. Il est nécessaire d'anti-quoter ce caractère dans la fonction system() car celle-ci utilise en argument une chaîne de caractères C déjà quotée par '"', d'où la présence du \".

La commande system() n'accepte qu'une seule chaîne de caractères en argument et ne permet donc pas d'introduire plusieurs arguments dynamiques comme le fait la fonction printf(). Si tel est le cas, il faut alors coupler la fonction system() avec la fonction sprintf(). Cette dernière permettra de construire à la convenance du programmeur la chaîne finale qui sera utilisée par la fonction system().

Exemple:

char commande[BUFSIZ]; sprintf(commande, "%s %s", argv[1], argv[2]); system(commande); argv[1] et argv[2] sont respectivement les chaînes de caractères :ppp-stud: et /infres/admin/ppp/ppp.map mises en premier et second argument du nom du programme utilisateur.

Fonction popen()

L'inconvénient majeur de la fonction system() est que le programme appelant ne contrôle ni en entrée ni en sortie, les données traîtées par la commande. La fonction popen() permet de pallier cette insuffisance. De manière transparente, popen() ouvre un pipe avant d'appeler la commande, permettant ainsi au programme appelant de communiquer avec le programme appelé grâce à ce pipe.

La syntaxe est la suivante:

FILE * popen(char * commande, char * mode)
  1. FILE * indique que la fonction popen() retourne un pointeur sur une structure de type FILE, comme le fait la fonction fopen().
  2. commande représente la chaîne de caractères associée au nom de la commande Unix, éventuellement suivie de ses arguments, exactement comme pour la fonction system().
  3. mode correspond au mode d'entrée/sortie choisi: Ce mode a la même signification que celui qui est généralement utilisé dans la fonction fopen(filename, mode.

Exemple de lecture de données d'une commande restituées sur l'écran:

FILE *pp; if ((pp = popen("ps aux", "r") == NULL) { perror("popen"); exit(1); } while (fgets(buf, sizeof(buf), pp)) fputs(buf, stdout); pclose(pp);

Exemple d'écriture de données vers une commande à partir d'une saisie clavier:

FILE *pp; if ((pp = popen("/usr/ucb/mail", "w") == NULL) { perror("popen"); exit(1); } while (fgets(buf, sizeof(buf), stdin)) fputs(buf, pp); pclose(pp); La fonction pclose() permet de fermer le pipe, avec en argument le pointeur de fichier rendu initialement par popen().

Exercices

Exercice sur argc, argv

Exercice sur getopt()

Exercice sur system()

Exercice sur popen() et sort

Utiliser la fonction popen() pour trier le fichier de référence /infres/admin/ppp/ppp.map à l'aide de l'utilitaire Unix sort, faire "man sort".

Exercice sur popen() et awk


© (Copyright) Philippe Dax - 1996-2000 Last updated: Jan 23, 1996