Quelles sont les utilisations de la commande exec dans les scripts shell?

250

Quelqu'un peut-il expliquer à quoi servent la commande exec dans les scripts shell avec des exemples simples?

user2400564
la source
31
Les liens vers linux.about.com ne sont pas utiles. Ils ne précisent pas à distance en quoi l'exécution d'une commande ou d'un pipeline de commandes à l'aide de 'exec' diffère de leur exécution normale. D'où la question du PO "à quoi sert l'exec"?
Jonathan Hartley
2
Stack Overflow est un site pour les questions de programmation et de développement. Cette question semble être hors sujet car elle ne concerne pas la programmation ou le développement. Voir Quels sujets puis-je poser ici dans le centre d'aide. Peut-être que Super User ou Unix & Linux Stack Exchange seraient un meilleur endroit pour demander.
2018

Réponses:

281

La execcommande intégrée reflète les fonctions du noyau, il y en a une famille basée sur execve, qui est généralement appelée à partir de C.

execremplace le programme en cours dans le processus en cours, sans forking nouveau processus. Ce n'est pas quelque chose que vous utiliseriez dans chaque script que vous écrivez, mais cela peut être utile à l'occasion. Voici quelques scénarios que je l'ai utilisés;

  1. Nous voulons que l'utilisateur exécute un programme d'application spécifique sans accès au shell. Nous pourrions changer le programme de connexion dans / etc / passwd, mais nous souhaitons peut-être que le paramètre d'environnement soit utilisé à partir des fichiers de démarrage. Donc, dans (disons) .profile, la dernière déclaration dit quelque chose comme:

     exec appln-program

    alors maintenant, il n'y a pas de shell pour revenir. Même en cas de appln-programplantage, l'utilisateur final ne peut pas accéder à un shell, car il n'est pas là - il l'a execremplacé.

  2. Nous voulons utiliser un shell différent de celui de / etc / passwd. Aussi stupide que cela puisse paraître, certains sites ne permettent pas aux utilisateurs de modifier leur shell de connexion. Un site que je connais a fait démarrer tout le monde csh, et tout le monde vient d' .loginappeler dans leur (fichier de démarrage csh) ksh. Bien que cela ait fonctionné, cela a laissé un cshprocessus errant en cours et la déconnexion était en deux étapes, ce qui pouvait prêter à confusion. Nous l'avons donc changé en exec kshremplaçant simplement le programme c-shell par le korn shell, et rendu tout plus simple (il y a d'autres problèmes avec cela, comme le fait que le kshn'est pas un login-shell).

  3. Juste pour sauver des processus. Si nous appelons prog1 -> prog2 -> prog3 -> prog4etc. et ne revenons jamais en arrière, alors faisons de chaque appel un exécutable. Il économise des ressources (pas beaucoup, certes, sauf répétition) et rend l'arrêt plus simple.

Vous avez évidemment vu executilisé quelque part, peut-être que si vous montriez le code qui vous dérange, nous pourrions justifier son utilisation.

Edit : j'ai réalisé que ma réponse ci-dessus est incomplète. Il y a deux utilisations de execdans des shells comme kshet bash- utilisées pour ouvrir des descripteurs de fichiers. Voici quelques exemples:

exec 3< thisfile          # open "thisfile" for reading on file descriptor 3
exec 4> thatfile          # open "thatfile" for writing on file descriptor 4
exec 8<> tother           # open "tother" for reading and writing on fd 8
exec 6>> other            # open "other" for appending on file descriptor 6
exec 5<&0                 # copy read file descriptor 0 onto file descriptor 5
exec 7>&4                 # copy write file descriptor 4 onto 7
exec 3<&-                 # close the read file descriptor 3
exec 6>&-                 # close the write file descriptor 6

Notez que l'espacement est très important ici. Si vous placez un espace entre le nombre fd et le symbole de redirection, puis execrevient à la signification d'origine:

  exec 3 < thisfile       # oops, overwrite the current program with command "3"

Il y a plusieurs façons dont vous pouvez les utiliser, sur l' utilisation ksh read -uou print -u, sur bash, par exemple:

read <&3
echo stuff >&4
cdarke
la source
22
il y a aussi une autre utilisation que j'ai trouvée très pratique et qui mérite d'être mentionnée ici car elle concerne les applications Web en python et semble quelque chose entre vos réponses (géniales) 2 et 3. Je lance généralement des applications Web wsgi (disons django ou flask) via un superviseur appelant un gunicorn app: ce dernier nécessitant notoirement un certain nombre de variables d'environnement, il est beaucoup plus facile et plus facile de faire fonctionner gunicorn à partir d'un script shell qui configure tout et finalement exec gunicornredonne le bon pid au superviseur.
gru
1
Les docs disent que execpeut être utilisé pour la redirection:> Si la commande n'est pas spécifié, aucune redirections prennent effet dans la coquille en cours, et l'état de retour est 0. En cas d'erreur de redirection, l'état de retour est 1. Mais comment fait execfonctionne réellement pour changer un descripteur de fichier? Pourquoi cette commande particulière est-elle choisie pour cette tâche? (Markdown échoue en ce moment?)
Ray
@Ray: le mieux que je puisse faire: pubs.opengroup.org/onlinepubs/009604599/utilities/exec.html . Si vous avez besoin de savoir comment, regardez le code source du shell.
cdarke
7
Une autre utilisation: rediriger toutes les sorties d'un script vers un fichier journalexec >.\logfilename.log 2>&1
Hogan
1
@Carmageddon: &>est une bashextension (voir man bash) et votre exemple est équivalent à exec >/var/log/userdata.log 2>&1. En d'autres termes, il redirige stdout et stderr vers ce fichier. Les commandes qui suivent hériteront de ces redirections à moins qu'elles ne soient réinitialisées, mais elles seront exécutées.
cdarke le
41

Juste pour augmenter la réponse acceptée par une brève réponse courte adaptée aux débutants, vous n'avez probablement pas besoin exec.

Si vous êtes toujours là, la discussion suivante devrait, espérons-le, révéler pourquoi. Quand tu cours, dis,

sh -c 'command'

vous exécutez une shinstance, puis démarrez en commandtant qu'enfant de cette shinstance. Une fois commandterminée, l' shinstance se termine également.

sh -c 'exec command'

exécute une shinstance, puis remplace cette shinstance par le commandbinaire et l'exécute à la place.

Bien entendu, ces deux éléments sont inutiles dans ce contexte limité; tu veux simplement

command

Dans certaines situations marginales, vous souhaitez que le shell lise son fichier de configuration ou, d'une manière ou d'une autre, configure l'environnement comme préparation à l'exécution command. C'est à peu près la seule situation où exec commandest utile.

#!/bin/sh
ENVIRONMENT=$(some complex task)
exec command

Cela fait des choses pour préparer l'environnement afin qu'il contienne ce qui est nécessaire. Une fois cela fait, l' shinstance n'est plus nécessaire, et c'est donc une optimisation (mineure) de simplement remplacer l' shinstance par le commandprocessus, plutôt que de l' shexécuter en tant que processus enfant et de l'attendre, puis de quitter dès qu'elle se termine.

De même, si vous souhaitez libérer autant de ressources que possible pour une commande lourde à la fin d'un script shell, vous pouvez souhaiter execcette commande comme optimisation.

Si quelque chose vous oblige à exécuter shmais que vous vouliez vraiment exécuter autre chose, exec something elsec'est bien sûr une solution de contournement pour remplacer l' shinstance indésirable (comme par exemple si vous vouliez vraiment exécuter votre propre spiffy goshau lieu de shmais le vôtre n'est pas répertorié /etc/shells, vous pouvez donc ne le spécifiez pas comme shell de connexion).

La deuxième utilisation de execpour manipuler les descripteurs de fichiers est un sujet distinct. La réponse acceptée couvre bien cela; pour garder ce contenu autonome, je vais simplement me reporter au manuel pour tout ce qui execest suivi d'une redirection au lieu d'un nom de commande.

tripleee
la source
2
Résister à la tentation d'appeler votre propre coquille spiffy bush. Bien sûr, cela s'applique à bashou généralement à tout shell Unix populaire; bien que, comme le note @anishsane , Bash optimise secrètement bash -c 'command'en le faisant exec command.
tripleee
1
Le code de sortie du shell est généralement le code de sortie de la dernière commande qu'il a exécutée. Bien sûr, si le shell ne s'exécute pas ou n'exécute pas la commande, l'état de sortie du shell reflétera cela avec un code d'erreur approprié.
tripleee
2
@JonathanLeffler Je documente délibérément un contre-modèle que je vois dans les questions des débutants. Celui-ci a été provoqué par ce doublon, mais je l'ai déjà vu, donc je voulais couvrir cela spécifiquement.
tripleee
2
@JonathanLeffler Tweak mineur de formulation; est-ce suffisant, pensez-vous? Merci pour les commentaires.
tripleee
2
Merci - J'ai ajouté un autre bref paragraphe sur cette optimisation. Ce n'est pas vraiment clair pour moi si vous avez d'autres objections, ou si vous souhaitez simplement expliquer les choses sous un angle différent.
tripleee du