Que fait une commande "exec"?

108

Je ne comprends pas la commande bash exec. Je l'ai vu utilisé dans des scripts pour rediriger toutes les sorties vers un fichier (comme indiqué dans ceci ). Mais je ne comprends pas comment ça marche ou ce que ça fait en général. J'ai lu les pages de manuel mais je ne les comprends pas.

becko
la source
Êtes-vous familier avec quel processus est?
fkraiem
1
@fkraiem que voulez-vous dire?
Becko
Désolé je voulais dire "quoi". : p Mais la réponse semble être non.
fkraiem
Mais en réalité, votre script utilise execune manière particulière, qui peut être expliquée beaucoup plus simplement, je vais écrire une réponse.
fkraiem
1
Connexes: unix.stackexchange.com/q/296838/85039
Sergiy Kolodyazhnyy

Réponses:

88

man bash dit:

exec [-cl] [-a name] [command [arguments]]
      If command is specified, it replaces the shell.  No new  process
      is  created.  The arguments become the arguments to command.  If
      the -l option is supplied,  the  shell  places  a  dash  at  the
      beginning  of  the  zeroth  argument passed to command.  This is
      what login(1) does.  The -c option causes command to be executed
      with  an empty environment.  If -a is supplied, the shell passes
      name as the zeroth argument to the executed command.  If command
      cannot  be  executed  for  some  reason, a non-interactive shell
      exits, unless the execfail shell option  is  enabled.   In  that
      case,  it returns failure.  An interactive shell returns failure
      if the file cannot be executed.  If command  is  not  specified,
      any  redirections  take  effect  in  the  current shell, and the
      return status is 0.  If there is a redirection error, the return
      status is 1.

Ce qui est important, ce sont les deux dernières lignes: si vous exécutez tout execseul, sans commande, les redirections s’appliqueront simplement au shell actuel. Vous savez probablement que lorsque vous exécutez command > file, la sortie de commandest écrite au filelieu de sur votre terminal (on parle de redirection ). Si vous l'exécutez à la exec > fileplace, la redirection s'applique à l'ensemble du shell: toute sortie produite par le shell est écrite au filelieu de sur votre terminal. Par exemple ici

bash-3.2$ bash
bash-3.2$ exec > file
bash-3.2$ date
bash-3.2$ exit
bash-3.2$ cat file
Thu 18 Sep 2014 23:56:25 CEST

Je commence d'abord un nouveau bashshell. Ensuite, dans ce nouveau shell, je lance exec > file, de sorte que toutes les sorties soient redirigées file. En effet, après cela, je cours datemais je n’obtiens aucune sortie, car la sortie est redirigée vers file. Ensuite, je quitte mon shell (pour que la redirection ne s'applique plus) et je constate que filecontient effectivement le résultat de la datecommande que j'ai exécutée précédemment.

fkraiem
la source
43
Ceci n'est qu'une explication partielle. execsert également à remplacer le processus shell actuel par une commande, de sorte que le parent aille de l’avant et que l’enfant possède le pid. Ce n'est pas seulement pour la redirection. S'il vous plaît ajouter cette information
Sergiy Kolodyazhnyy
3
Pour faire suite au commentaire de @ SergiyKolodyazhnyy, l'exemple que je viens de rencontrer et qui m'a amené à cette page est un fichier docker-entrypoint.sh, où, après avoir effectué diverses actions sur la configuration de nginx, la dernière ligne du script est exec nginx <various nginx arguments>. Cela signifie que nginx reprend le pid du script bash et maintenant, nginx est le processus principal d'exécution du conteneur, pas le script. Je suppose que ceci est juste pour la propreté, à moins que quelqu'un d'autre connaisse une raison plus concrète pour cela?
Luke Griffiths
1
@Luke Ceci s'appelle "script wrapper". Un exemple de cela est également gnome-terminal, qui au moins sur 14.04 avait un script de wrapper pour configurer des arguments. Et c’est leur seul but, vraiment - mettre en scène les arts et l’environnement. Un autre cas serait de nettoyer - tuez d’abord l’instance précédente d’un processus et en lancer un nouveau
Sergiy Kolodyazhnyy
Un autre execexemple similaire à l' nginxexemple donné par @LukeGriffiths est le ~/.vnc/xstartupscript qui vncserverutilise pour configurer un processus de serveur VNC, puis exec gnome-sessionou exec startkdeet ainsi de suite.
Trevor Boyd Smith le
@ LukeGriffiths, la principale raison d' execun script de démarrage de conteneur est que le PID 1, ENTRYPOINT du conteneur, a une signification particulière dans Docker. C'est un processus principal qui reçoit des signaux et, lorsqu'il existe, le conteneur se ferme également. execjuste un moyen de shsortir de cette chaîne de commande et de faire du démon le processus principal du conteneur.
Kkm
45

exec est une commande avec deux comportements très distincts, selon qu’au moins un argument est utilisé avec elle ou pas du tout.

  • Si au moins un argument est passé, le premier est utilisé comme nom de commande et exectente de l'exécuter en tant que commande, en transmettant les arguments restants, le cas échéant, à cette commande et en gérant les redirections, le cas échéant.

  • Si la commande passée en tant que premier argument n'existe pas, le shell actuel, pas seulement la commande exec, se termine en erreur.

  • Si la commande existe et qu'elle est exécutable, elle remplace le shell actuel. Cela signifie que si execapparaît dans un script, les instructions qui suivent l'appel exec ne seront jamais exécutées (sauf si elles execsont elles-mêmes dans un sous-shell). execne revient jamais. Les pièges tels que "EXIT" ne seront pas déclenchés non plus.

  • Si aucun argument n'est passé, execest uniquement utilisé pour redéfinir les descripteurs de fichier shell actuels. Le shell continue après le exec, contrairement au cas précédent, mais l'entrée standard, la sortie, l'erreur ou tout autre descripteur de fichier redirigé prend effet.

  • Si certaines des redirections utilisent /dev/null, toute entrée de celle-ci renverra EOF et toute sortie vers celle-ci sera supprimée.

  • Vous pouvez fermer les descripteurs de fichier en utilisant -comme source ou destination, par exemple exec <&-. Les lectures ou écritures suivantes échoueront alors.

Voici deux exemples:

echo foo > /tmp/bar
exec < /tmp/bar # exec has no arguments, will only affect current shell descriptors, here stdin
cat # simple command that read stdin and write it to stdout

Ce script affichera "foo" en tant que commande cat, au lieu d'attendre la saisie de l'utilisateur, comme cela aurait été le cas habituel, prendra son entrée dans le fichier / tmp / bar qui contient foo.

echo foo > /tmp/bar
exec wc -c < /tmp/bar # exec has two arguments, the control flow will switch to the wc command
cat

Ce script affiche 4(le nombre d'octets dans / tmp / bar) et se termine immédiatement. La catcommande ne sera pas exécutée.

jlliagre
la source
4
`Certains vieux messages ne vieillissent jamais vraiment ... +1.
Cbhihe
3
Si certaines des redirections utilisent / dev / null, le descripteur de fichier associé est fermé. Non, il redirige vraiment vers / depuis /dev/null, donc les écritures réussissent toujours et les lectures retournent EOF. close(2)sur un fd, les appels système en lecture / écriture renverraient des erreurs, ce que vous feriez avec, exec 2>&-par exemple.
Peter Cordes
2
Essayez-le vous-même: exec 3</dev/null; ls -l /proc/self/fdnotez que le fd 3 sera ouvert en lecture seule sur / dev / null. Puis fermez-le à nouveau avec exec 3<&-, et vous verrez (avec à ls -l /proc/$$/fdnouveau) que votre processus shell n'a plus de fd 3. (fermer stdin avec exec <&-peut être utile dans les scripts, mais interactivement c'est une déconnexion.)
Peter Cordes
@PeterCordes Vous avez absolument raison. Réponse mise à jour. Merci!
jlliagre
1
Cette réponse est excellente car elle explique les deux cas d'utilisation de execla réponse la plus votée actuelle ne parle que d'un cas d'utilisation et l'autre réponse de g_p ne parle que de l'autre cas d'utilisation. Et cette réponse est agréable et concise / lisible pour un sujet aussi complexe.
Trevor Boyd Smith le
33

Pour comprendre, execvous devez d'abord comprendre fork. J'essaie de rester bref.

  • Lorsque vous arrivez à un embranchement, vous avez généralement deux options. Les programmes Linux atteignent cette fourchette lorsqu'ils lancent un fork()appel système.

  • Les programmes normaux sont des commandes système existant sous une forme compilée sur votre système. Lorsqu'un tel programme est exécuté, un nouveau processus est créé. Ce processus enfant a le même environnement que son parent, seul le numéro d'identification du processus est différent. Cette procédure s'appelle une fourchette .

  • Forking fournit un moyen pour un processus existant de démarrer un nouveau. Cependant, il peut y avoir des situations où un processus enfant ne fait pas partie du même programme que le processus parent. Dans ce cas, execest utilisé. exec remplacera le contenu du processus en cours d'exécution par les informations d'un programme binaire.
  • Après le processus de forking, l'espace d'adressage du processus enfant est écrasé par les nouvelles données de processus. Cela se fait par un appel exec au système.
g_p
la source
3
pouvez-vous expliquer pourquoi execpeut rediriger une sortie de script, comme dans le lien que j'ai posté?
Becko
1
J'ai trouvé cela peu clair "Cependant, il peut y avoir des situations où un processus enfant ne fait pas partie du même programme que le processus parent"
cdosborn
6

Dans bash, si vous faites help exec:

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

    Options:
      -a name   pass NAME as the zeroth argument to COMMAND
      -c        execute COMMAND with an empty environment
      -l        place a dash in the zeroth argument to COMMAND

    If the command cannot be executed, a non-interactive shell exits, unless
    the shell option `execfail' is set.

    Exit Status:
    Returns success unless COMMAND is not found or a redirection error occurs.

Le bit pertinent:

If COMMAND is not specified, any redirections take effect in the current shell.

execest un shell intégré , qui est l’équivalent du shell de la execfamille des appels système dont parle G_P (et dont vous semblez avoir lu les pages de manuel). Il ne dispose que de la fonctionnalité mandatée par POSIX qui affecte le shell actuel si aucune commande n'est spécifiée.

muru
la source