web-dev-qa-db-fra.com

la commande exec bin bash

Je vérifiais un script Shell et ai remarqué la commande ci-dessous - exec. la commande exec exécute la cmdline mais je me demande quelle est la commande :-/bin/bash à faire ici.

cmdline="$@"
    exec ${cmdline:-/bin/bash}
3
user1050619

Comment fonctionne le code et pourquoi

Il y a 3 choses principales qui se passent ici:

  • $@ est une variable shell spéciale qui s'étend à tous les arguments de ligne de commande du script.
  • ${cmdline:-/bin/bash} est l'une des structures d'expansion des paramètres; Si la variable cmdlineest non définie ou vide, la totalité de la partie ${} est remplacée par celle qui se trouve après le signe -, dans ce cas /bin/bash; c'est en quelque sorte un raccourci pour if, ou opérateur ternaire dans d'autres langages de programmation (pas exactement, mais assez bon pour la comparaison)
  • execest utilisé pour générer un processus qui dépassera le PID du processus actuel, c’est-à-dire qu'il remplacera simplement votre processus de script par ce qui était à l'intérieur de ce ${}

En regroupant tout cela, le code prend simplement des arguments de ligne de commande et les exécute. S'il n'y a pas d'argument de ligne de commande dans un script, vous obtenez un bashinteractive Shell. Notez que vous pouvez également passer des options à execqui sont mentionnées dans la documentation - comparez ./exec_script.sh -c env et ./exec_script.sh env.

Bon en théorie, mauvais en pratique

L'approche elle-même peut sembler compliquée, mais il est fréquent de voir cette approche avec execdans scripts d'encapsulation - un script configure l'environnement et vérifie les variables avant de tout organiser pour exécuter la commande réelle. La différence ici réside dans le fait que la commande de scripts wrapper est définie - un script wrapper configure généralement un environnement et des arguments pour l'exécution d'un seul programme particulier.

En revanche, ce script vise à exécuter tout ce que l'utilisateur met en ligne de commande. Et cela pose un problème à cause du fonctionnement de Shell - Si vous avez des arguments de ligne de commande contenant des caractères spéciaux, la commande que vous souhaitez exécuter risque de ne pas fonctionner. Voici ce que je veux dire:

# This is how it's supposed to work
$ printf 'one%stwo' $'\t'                                                              
one     two

# This is how it works with unquoted parameter expansion
$ ./exec_script.sh  printf 'one%stwo' $'\t'                                            
onetwo

Imaginez si vous essayez d'utiliser ce script pour exécuter my_cool_command filename$'\t'with$'\t'tabs.txt; au mieux - les commandes sont interrompues, mais si vous avez également un fichier filenamewithtab.txt dans votre dossier actuel, my_cool_command fonctionnera avec un fichier complètement incorrect. Et citer l'expansion des paramètres n'aide pas non plus, car alors il casse:

$ ./exec_script.sh  printf 'one%stwo' $'\t'                                            
./exec_script.sh: line 4: exec: printf one%stwo     : not found

Documentation pertinente

Voici une partie pertinente sur le développement de paramètres à partir du manuel bash(version 4.3):

$ {paramètre: -Word}

Utiliser les valeurs par défaut. Si le paramètre est unset ou null, le développement de Word est remplacé. Sinon, la valeur du paramètre est substituée.

Section "Paramètres spéciaux":

@ S'agrandit jusqu'aux paramètres de position, en commençant par un. Lorsque le développement se produit entre guillemets doubles, chaque paramètre se développe dans un mot distinct. C'est-à-dire que "$ @" équivaut à "$ 1" "$ 2" ... Si le développement entre guillemets doubles se produit dans un mot, le développement du premier paramètre est joint au début du mot d'origine, et le développement du dernier paramètre est joint à la dernière partie du mot d'origine. Quand il n'y a pas de paramètre de position, "$ @" et $ @ sont étendus à néant (c'est-à-dire qu'ils sont supprimés).

De la section "Commandes intégrées Shell":

exec [-cl] [-a nom] [commande [arguments]]

Si commande est spécifié, il remplace le shell. Aucun nouveau processus n'est créé. Les arguments deviennent les arguments à commander. Si l'option -l est fournie, le shell place un tiret au début de l'argument zéro transmis à la commande. C'est ce que login (1) fait. L'option -c entraîne l'exécution de la commande avec un environnement vide. Si -a est fourni, le shell transmet le nom en tant qu'argument zéro à la commande exécutée. Si la commande ne peut pas être exécutée pour une raison quelconque, un shell non interactif se ferme, sauf si l'option shell execfail est activée. Dans ce cas, il renvoie un échec. Un shell interactif renvoie un échec si le fichier ne peut pas être exécuté. Si la commande n'est pas spécifiée, les redirections prennent effet dans le shell actuel et le statut de retour est 0. S'il existe une erreur de redirection, le statut de retour est 1.

Conclusion et réflexions

Ce script lui-même a une bonne idée en théorie, mais médiocre en pratique. La commande execfonctionnera bien dans les scripts wrapper, et en fait, en tant qu’un des principaux utilisateurs des sites Unix et Linux, Gilles , mentionné "... exec économise également un peu de mémoire (et d’autres ressources telles que en tant que PID, etc.) car il n’est pas nécessaire de garder un Shell supplémentaire avec tout ce qui reste à faire ". Mais dans ce cas, le script vise à réinventer la roue et à faire ce que Shell fait déjà assez bien - c’est-à-dire exécuter des commandes avec des arguments.

2