GNU/Linux >> Tutoriels Linux >  >> Linux

Que se passe-t-il exactement lorsque j'exécute un fichier dans le shell ?

Donc, je pensais avoir une bonne compréhension de cela, mais je viens de faire un test (en réponse à une conversation où je n'étais pas d'accord avec quelqu'un) et j'ai constaté que ma compréhension était erronée…

Avec le plus de détails possible que se passe-t-il exactement lorsque j'exécute un fichier dans mon shell ? Ce que je veux dire, c'est que si je tape :./somefile some arguments dans mon shell et appuyez sur retour (et somefile existe dans le cwd, et j'ai des autorisations de lecture + exécution sur somefile ) alors que se passe-t-il sous le capot ?

J'ai pensé la réponse était :

  1. Le shell fait un appel système à exec , en passant le chemin vers somefile
  2. Le noyau examine somefile et regarde le nombre magique du fichier pour déterminer s'il s'agit d'un format que le processeur peut gérer
  3. Si le nombre magique indique que le fichier est dans un format que le processeur peut exécuter, alors
    1. un nouveau processus est créé (avec une entrée dans la table des processus)
    2. somefile est lu/mappé en mémoire. Une pile est créée et l'exécution saute au point d'entrée du code de somefile , avec ARGV initialisé à un tableau de paramètres (un char** , ["some","arguments"] )
  4. Si le nombre magique est un shebang alors exec() génère un nouveau processus comme ci-dessus, mais l'exécutable utilisé est l'interpréteur référencé par le shebang (par exemple /bin/bash ou /bin/perl ) et somefile est passé à STDIN
  5. Si le fichier n'a pas de numéro magique valide, une erreur du type "fichier invalide (mauvais numéro magique) :erreur de format d'exécution" se produit

Cependant, quelqu'un m'a dit que si le fichier est en texte brut, le shell essaie d'exécuter les commandes (comme si j'avais tapé bash somefile ). Je n'y croyais pas, mais je viens d'essayer, et c'était correct. J'ai donc clairement des idées fausses sur ce qui se passe réellement ici, et j'aimerais comprendre les mécanismes.

Que se passe-t-il exactement lorsque j'exécute un fichier dans mon shell ? (avec autant de détails c'est raisonnable...)

Réponse acceptée :

La réponse définitive à « comment les programmes sont exécutés » sur Linux est la paire d'articles sur LWN.net intitulé, assez étonnamment, Comment les programmes sont exécutés et Comment les programmes sont exécutés :les binaires ELF. Le premier article traite brièvement des scripts. (Strictement parlant, la réponse définitive se trouve dans le code source, mais ces articles sont plus faciles à lire et fournissent des liens vers le code source.)

Une petite expérimentation montre que vous avez à peu près bien compris et que l'exécution d'un fichier contenant une simple liste de commandes, sans artifice, doit être gérée par le shell. La page de manuel execve(2) contient le code source d'un programme de test, execve; nous allons l'utiliser pour voir ce qui se passe sans shell. Tout d'abord, écrivez un script de test, testscr1 , contenant

#!/bin/sh

pstree

et un autre, testscr2 , ne contenant que

pstree

Rendez-les tous les deux exécutables et vérifiez qu'ils s'exécutent tous les deux à partir d'un shell :

chmod u+x testscr[12]
./testscr1 | less
./testscr2 | less

Maintenant réessayez en utilisant execve (en supposant que vous l'ayez construit dans le répertoire courant) :

./execve ./testscr1
./execve ./testscr2

testscr1 fonctionne toujours, mais testscr2 produit

execve: Exec format error

Cela montre que le shell gère testscr2 différemment. Cependant, il ne traite pas le script lui-même, il utilise toujours /bin/sh pour faire ça; cela peut être vérifié en reliant testscr2 à less :

./testscr2 | less -ppstree

Sur mon système, j'obtiens

    |-gnome-terminal--+-4*[zsh]
    |                 |-zsh-+-less
    |                 |     `-sh---pstree

Comme vous pouvez le voir, il y a le shell que j'utilisais, zsh , qui a commencé less , et un deuxième shell, simple sh (dash sur mon système), pour exécuter le script, qui a exécuté pstree . En zsh ceci est géré par zexecve dans Src/exec.c :le shell utilise execve(2) pour essayer d'exécuter la commande, et si cela échoue, il lit le fichier pour voir s'il a un shebang, le traitant en conséquence (ce que le noyau aura également fait), et si cela échoue, il essaie d'exécuter le fichier avec sh , tant qu'il n'a lu aucun octet zéro du fichier :

        for (t0 = 0; t0 != ct; t0++)
            if (!execvebuf[t0])
                break;
        if (t0 == ct) {
            argv[-1] = "sh";
            winch_unblock();
            execve("/bin/sh", argv - 1, newenvp);
        }

bash a le même comportement, implémenté dans execute_cmd.c avec un commentaire utile (comme souligné par taliezin):

Exécutez une commande simple qui, espérons-le, est définie dans un fichier disque
quelque part.

  1. fork ()
  2. connecter les tuyaux
  3. recherchez la commande
  4. faire des redirections
  5. execve ()
  6. Si le execve a échoué, voyez si le fichier est en mode exécutable.
    Si c'est le cas, et qu'il ne s'agit pas d'un répertoire, exécutez son contenu comme
    un script shell.

POSIX définit un ensemble de fonctions, connu sous le nom de exec(3) fonctions, qui enveloppent execve(2) et fournir également cette fonctionnalité ; voir la réponse de muru pour plus de détails. Sous Linux, au moins ces fonctions sont implémentées par la bibliothèque C, pas par le noyau.

Connexe :le but du mot-clé "do" dans Bash for loops ?
Linux
  1. Quel est le but du fichier .bashrc sous Linux

  2. Qu'advient-il d'un descripteur de fichier ouvert sous Linux si le fichier pointé est déplacé ou supprimé

  3. Quelle est la bonne façon d'utiliser inotify ?

  4. Comment exécuter un fichier sans extension .sh dans le shell

  5. À quoi sert l'autorisation d'exécution ?

Qu'est-ce que le Shell sous Linux ?

Comment exécuter un fichier .sh au démarrage de la session ?

Que se passe-t-il en arrière-plan lorsque vous exécutez la commande "useradd" sous Linux

Qu'est-ce qu'un fichier .sh ?

Que se passe-t-il lorsqu'un thread bifurque ?

Quel est le shell par défaut de Busybox ?