web-dev-qa-db-fra.com

Écrire un shell basique

Pour ma classe, je dois créer un shell de base similaire à bash qui permettra à l’utilisateur d’appeler des commandes telles que ls, sleep, etc. .. Je recherche des ressources sur la procédure à suivre: tutoriels, texte d’aide, code exemple ou juste quelques informations générales sur la façon de commencer ... Est-ce que quelqu'un a des liens ou des informations pour m'aider?

21
Bobby S

Le manuel glibc contient des informations utiles sur la mise en œuvre du contrôle des tâches dans le shell: http://www.gnu.org/software/libc/manual/html_node/Implementing-a-Shell.html#Implementing-a-Shell

24
Peter Eisentraut

Cela dépend vraiment de la simplicité de votre Shell. Si vous n’avez pas besoin de contrôle de travail (c’est-à-dire d’arrière-plan) ou de tuyaux, c’est très simple. Voici un exemple:

#include <stdio.h>
#include <stdlib.h>

#define MAX_LENGTH 1024

int main(int argc, char *argv[]) {
  char line[MAX_LENGTH];

  while (1) {
    printf("$ ");
    if (!fgets(line, MAX_LENGTH, stdin)) break;
    system(line);
  }

  return 0;
}

Vous pouvez sortir de l'exemple ci-dessus avec CTRL-D. Pour ajouter des commandes intégrées telles que exit ou cd , vous devez marquer la ligne à l'aide de strtok () et regarder le premier jeton. Voici un exemple plus compliqué avec ces commandes ajoutées:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifdef _WIN32
#include <windows.h>
#define chdir _chdir

#else
#include <unistd.h>
#endif

#define MAX_LENGTH 1024
#define DELIMS " \t\r\n"

int main(int argc, char *argv[]) {
  char *cmd;
  char line[MAX_LENGTH];

  while (1) {
    printf("$ ");
    if (!fgets(line, MAX_LENGTH, stdin)) break;

    // Parse and execute command
    if ((cmd = strtok(line, DELIMS))) {
      // Clear errors
      errno = 0;

      if (strcmp(cmd, "cd") == 0) {
        char *arg = strtok(0, DELIMS);

        if (!arg) fprintf(stderr, "cd missing argument.\n");
        else chdir(arg);

      } else if (strcmp(cmd, "exit") == 0) {
        break;

      } else system(line);

      if (errno) perror("Command failed");
    }
  }

  return 0;
}

Vous pouvez étendre cela en ajoutant d'autres commandes intégrées ou en prenant en charge des éléments tels que cd avec des arguments out à modifier dans votre répertoire personnel. Vous pouvez également améliorer la commande Invite en ajoutant des informations telles que le répertoire actuel.

En guise de remarque, un moyen simple d’ajouter un historique des commandes et des fonctionnalités de modification de ligne consiste à utiliser la bibliothèque GNU readline .

10
jcoffland

J'ai écrit un shell très basique pour le projet HelenOS . Il présente les caractéristiques suivantes:

  • Édition de ligne/historique
  • Buit dans les commandes/commandes chargeables
  • Chemin de recherche pour trouver des commandes externes
  • EXTREMELY scripting de base
  • Implémentations simplifiées de la plupart des utilitaires GNU (en partant de zéro) sous forme de fonctions intégrées.

La majeure partie est implémentée sur un framework très simple, réutilisable, construit autour de pointeurs de fonction. Au minimum, vous aurez besoin d'une "sortie" ou d'un "quitter" intégré pour que quelqu'un puisse réellement sortir de Shell, ainsi que "cd" et "pwd". Un «export»/«déclarer» intégré aurait également un sens.

Vous pouvez regarder le code (BSD) sous licence ici . Ou téléchargez le référentiel, c'est dans uspace/app/bdsh. Je peux probablement creuser la dernière version de Linux fonctionnelle avant de la porter si vous en avez besoin. La plus grande différence réside dans le fait que la version de HelenOS utilise un éditeur de ligne développé localement, task_spawn () au lieu de execve ()/posix_spawn (), etc. Le reste est portable. Il a été conçu à l’origine pour faciliter le test des fonctionnalités et leur interactivité. Je n'ai pas mis en place de contrôle des tâches, car ce n'était pas nécessaire. Cela pourrait être réalisé trivialement, cependant.

Si vous voulez étudier un «vrai» Shell, je vous recommande vivement de regarder dash, vous le trouverez beaucoup plus simple à comprendre que de plonger directement dans le code de bash.

De manière anecdotique, «bdsh» signifie «brain dead Shell».

4
Tim Post

Si vous commencez, essayez http://stephen-brennan.com/2015/01/16/write-a-Shell-in-c/ et plus de détails http: //www.gnu .org/software/libc/manual/html_node/Data-Structures.html # Data-Structures .

De même, tout en apprenant à programmer un shell en C/C++, prenez l’habitude de vous référer aux pages de manuel des commandes.

2
Laschet Jain

Vous pouvez regarder BusyBox pour de très petites implémentations de Shell.

2
R..

Bash fournit seul très peu de commandes: cd, pushd, popd, les routines de traitement des variables (set et $x) et tous les éléments de flux de contrôle tels que les boucles et les conditions. Presque toutes les autres commandes se trouvent dans le $PATH.

Sauf indication contraire de l'affectation, ignorez les variables et le flux de contrôle. Fournissez simplement un REPL qui recherche dans $PATH et exécute ce que l'utilisateur entre (probablement via posix_spawn()) et transmet les arguments de la ligne de commande.

0
chrisaycock

Réponse Lowball: 

Si le programme est très simple, des appels système simples peuvent être implémentés comme un script avec la commande "system("putdesiredcommandhere");"

Lorsque vous installez "printf" dans un programme, vous effectuez un simple appel système à l'aide de stdio.h.

Un petit exemple de code suit.

#include <stdio.h>
#include <stdlib.h>
main ()
{
    system ("clear");
    system ("echo this is an example of a basic system call");
    printf ("just as you've always done.\n");

    return 0;
}

En utilisant cette méthode, vous pouvez transcrire des scripts bash ou csh dans un programme c. Il faudrait utiliser un appel système pour chaque ligne du script. 

0
agx