Cas d'utilisation / exemple pratique pour l'exec Bash 'intégré


12

Considérez ceci dans la documentation de l'exec intégré de Bash:

exec remplace le shell sans créer de nouveau processus

Veuillez fournir un cas d'utilisation / un exemple pratique. Je ne comprends pas comment cela a du sens.

J'ai googlé et trouvé au sujet de la redirection d' E / S . Pouvez-vous l'expliquer mieux?


Réponses:


18

execest souvent utilisé dans les scripts shell qui agissent principalement comme des wrappers pour démarrer d'autres binaires. Par exemple:

#!/bin/sh

if stuff;
    EXTRA_OPTIONS="-x -y -z"
else
    EXTRA_OPTIONS="-a foo"
fi

exec /usr/local/bin/the.real.binary $EXTRA_OPTIONS "$@"

de sorte qu'après l'exécution de l'encapsuleur, le "vrai" binaire prend le relais et il n'y a plus de trace du script d'encapsuleur qui occupait temporairement le même emplacement dans la table de processus. Le "vrai" binaire est un enfant direct de tout ce qui l'a lancé au lieu d'un petit-enfant.

Vous mentionnez également la redirection d'E / S dans votre question. C'est un cas d'utilisation assez différent execet n'a rien à voir avec le remplacement du shell par un autre processus. Quand execn'a pas d'arguments, comme ceci:

exec 3>>/tmp/logfile

les redirections d'E / S sur la ligne de commande prennent effet dans le processus de shell actuel, mais le processus de shell actuel continue de fonctionner et passe à la commande suivante du script.


1
Vous pouvez dire que les deux cas sont liés en ce que pour les deux, execle shell ne doit pas exécuter l'action (exécuter une commande ou effectuer une redirection) dans un processus enfant, mais dans le même processus.
Stéphane Chazelas

5

J'ai utilisé un shell execintégré pour obtenir un ID de processus (PID) pour un programme Java. Il y a peut-être un moyen d'obtenir le PID depuis Java maintenant, mais il y a plusieurs années, il n'y en avait pas. Une fois qu'un processus a son propre PID, il peut l'écrire dans un fichier PID (recherchez /var/run/les noms de fichiers avec un suffixe «.pid») pour permettre aux programmes de gestion de connaître le PID du processus en cours d'exécution et pour empêcher une deuxième instance. du même serveur de s'exécuter. Cela fonctionne comme ceci:

exec java -cp=YourServer.jar StartClass -p $$

Le code de la main()méthode de classe StartClassgère l'analyse des arguments et peut trouver son propre ID de processus.


2

Pour le plaisir, exécutez le programme suivant (traduit dans la langue d'implémentation de votre choix) en arrière-plan sur un système avec une comptabilité et des limites de processus utilisateur.

while(true) fork();

Maintenant que chaque emplacement de la table de processus que vous êtes autorisé à utiliser est plein de copies de ce programme en cours d'exécution, comment comptez-vous le supprimer? Le lancement de kill (1) nécessite un autre emplacement de processus, que vous ne pouvez pas avoir. Il serait certainement pratique que le shell se remplace par la commande kill ...

exec /bin/kill -9 -1

(Suppose que votre système a kill (1) dans / bin / kill. "Exec` qui kill` -9 -1 "est potentiellement plus sûr.) Cela envoie SIGKILL à chaque processus que vous pouvez.

(Remarque: Ne vous déconnectez pas de votre shell de lancement à moins que les limites du processus ne permettent toujours une nouvelle connexion un emplacement de processus pour son shell. Cela peut être un peu plus difficile à nettoyer si vous le faites. Je ne l'ai certainement pas fait dans le début des années 90. Non.)


3
(1) Cette réponse serait légèrement meilleure si vous montriez réellement la execcommande qui serait utile dans cette situation. (2) Cette réponse est quelque peu archaïque; la killcommande est une commande intégrée dans bash depuis de nombreuses années, principalement en raison de cette préoccupation.
G-Man dit `` Réintègre Monica ''

@ G-Man: Vous comprenez que votre item (2) fait de cette réponse une réponse précise à l'OP?
Eric Towers

Non, je ne comprends pas ça. Veuillez me l'expliquer.
G-Man dit `` Réintègre Monica ''

4
Je ne vous suis pas. La question ne demande pas d'exemples pratiques de toutes les commandes intégrées de bash; il demande des exemples de exec- et le fait que ce killsoit un builtin n'a vraiment rien à voir avec le execbuiltin.
G-Man dit `` Réintègre Monica ''

1
Je viens de lire votre mise à jour de votre réponse. (1) Devinez quoi? Si la table de processus est pleine, la substitution de commande (par exemple, `which kill`) ne fonctionnera pas non plus. (2) BTW, le $(…)formulaire est recommandé par rapport au `…`formulaire. (3) Mais il n'y a rien de dangereux à deviner le répertoire. Si vous tapez accidentellement exec /binn/kill, vous obtiendrez simplement un message d'erreur et votre shell ne disparaîtra pas. (4) Mais vous n'avez même pas besoin de vous soucier du répertoire kill.  execUtilise $PATH, tout comme les commandes normales, exec kill …fonctionne donc (en supposant que vous en avez /bindans votre chemin de recherche).
G-Man dit `` Réintègre Monica ''

1
  • Ceci est similaire à l'exemple de Bruce qui a besoin de connaître le PID d'un processus:

    (cmdpid = $ BASHPID; (sleep 300; kill "$ cmdpid") & commande de longue durée )

    dans lequel vous

    1. Démarrer un sous-shell (l'extérieur (et )),
    2. Découvrez le PID du sous-shell. ( $$vous donnera le PID du shell principal.)
    3. Détachez un sous-sous-shell qui tue votre processus après une temporisation, et
    4. Exécutez une commande dans le processus du sous-shell que vous avez créé à l'étape 1.

    Cela s'exécutera long-running-command, mais uniquement pour une durée prédéterminée et limitée. 

  • C'est un peu frivole, mais si vous décidez que vous voulez être root (ou un autre utilisateur) pour le reste de votre session de connexion, vous le pourriez exec su.

    En fait, je peux imaginer un scénario où cela serait vraiment utile. Supposons que vous êtes connecté à un système distant et, pour une raison quelconque, il y a un problème avec la rupture de la connexion et le démarrage d'une nouvelle connexion. Par exemple, supposons que le système distant dispose d'un pare-feu qui suit un calendrier. Vous avez été autorisé à vous connecter lorsque vous l'avez fait, et les connexions établies ne sont pas fermées, mais à l'heure actuelle, les nouvelles connexions ne sont pas acceptées.

    Vous avez fait ce que vous vouliez faire et vous êtes prêt à vous déconnecter. Votre ami Bob est dans la pièce avec vous, et il veut travailler sur le système distant - mais il ne pourra pas se connecter. Ainsi, vous tapez exec su - bobet, lorsque l'invite de mot de passe apparaît, lui remettez le poste de travail. Il n'y a maintenant aucun processus avec votre UID (sauf si vous avez exécuté quelque chose en arrière-plan), donc Bob ne pourra pas jouer avec vos fichiers. Il aura effectivement pris en charge votre connexion (avec votre consentement et votre coopération).

    Remarques:

    • Bien sûr, cela ne fonctionnera pas si vous n'êtes pas autorisé à courir su.
    • Il sera enregistré, vous devrez donc peut-être expliquer vos motivations à quelqu'un. Puisque vous contournez la politique (la planification du pare-feu), vous pourriez avoir des ennuis.
    • Je ne garantis pas qu'il est 100% sécurisé. Par exemple, whoaffichera probablement toujours votre nom. Il est concevable que certains programmes (mal écrits) s'en servent pour penser que Bob est vous et lui donner accès à vos ressources.
    • Si le système effectue un audit, les actions de Bob peuvent être auditées sous votre nom.

Notez qu'en pratique dans la plupart des shells, (a;b)c'est déjà la même chose que (a;exec b)les shells optimisent la fourche pour la dernière commande d'un sous-shell. Les seules exceptions semblent être bashet mksh. L'utilisation execaide à le garantir.
Stéphane Chazelas
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.