Question commande exec bin bash


Je vérifiais un script shell et remarquais la commande ci-dessous - exec. la commande exec exécute la ligne de commande mais je me demande quel est le :-/bin/bash commande faites ici.

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

3
2017-10-20 19:13


origine




Réponses:


Comment fonctionne le code et pourquoi

Il y a 3 choses principales qui se passent ici:

  • $@ est une variable shell spéciale qui étend tous les arguments de ligne de commande au script
  • ${cmdline:-/bin/bash} est l'une des structures d'extension de paramètres; si cmdline variable est vide ou vide, le tout ${} partie est remplacée par tout ce qui vient après - signe, dans ce cas /bin/bash ; c'est une sorte de raccourci pour une instruction if ou un opérateur ternaire dans d'autres langages de programmation (pas exactement, mais assez bon pour la comparaison)
  • exec est utilisé pour générer un processus qui dépassera le PID du processus actuel, c'est-à-dire simplement remplacer votre processus de script par tout ce qui se trouve à l'intérieur ${}

En mettant tout cela ensemble, le code prend simplement les arguments de la ligne de commande et les exécute, et s'il n'y a pas d'arguments de ligne de commande dans le script, vous obtenez interactif bash coquille. Notez que vous pouvez également passer des options à exec qui sont mentionnés dans la documentation - comparer ./exec_script.sh -c env et ./exec_script.sh env.

Bon en théorie, mauvais en pratique

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

En revanche, ce script vise à exécuter tout ce que l'utilisateur place en ligne de commande. Et cela a un problème à cause de la façon dont fonctionne le shell - Avec des arguments de ligne de commande contenant des caractères spéciaux, la commande que vous souhaitez exécuter peut être interrompue. 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 - des pauses de commande, mais si vous avez aussi filenamewithtab.txt Fichier dans votre dossier actuel, my_cool_command fonctionnera sur le fichier complètement faux. Et citer le développement de 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 de l’extension des paramètres à partir de bash (version 4.3) manuel:

$ {paramètre: -word}

Utilisez les valeurs par défaut. Si le paramètre n'est pas défini ou nul, l'expansion du mot est substituée. Sinon, la valeur du paramètre est substituée.

Section "Paramètres spéciaux":

@ Développe les paramètres de position à partir de un. Lorsque l'expansion se produit entre guillemets, chaque paramètre se développe en un mot distinct. C'est-à-dire que "$ @" est équivalent à "$ 1" "$ 2" ... Si l'expansion entre guillemets se produit dans un mot, l'expansion du premier paramètre est jointe à la partie initiale du mot d'origine, et l'expansion du dernier paramètre est joint à la dernière partie du mot d'origine. Quand il n'y a pas de paramètres de position, "$ @" et $ @ se développent à rien (c'est-à-dire qu'ils sont supprimés).

Dans la section "Commandes intégrées de Shell":

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

Si la commande est spécifiée, elle 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 zeroth transmis à la commande. C'est ce que fait login (1). L'option -c provoque l'exécution de la commande avec un environnement vide. Si -a est fourni, le shell transmet nom comme argument zeroth à 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, toute redirection prend effet dans le shell en cours et le statut de retour est 0. En cas d'erreur de redirection, le statut de retour est 1.

Conclusion et pensées

Ce script lui-même a une bonne idée en théorie, mais pauvre en pratique. le exec commande fonctionnera bien dans les scripts wrapper, et en fait en tant que l'un des meilleurs utilisateurs sur le site Unix & Linux, Gilles , a mentionné "... exec sauve également un peu de mémoire (et d'autres ressources telles que les PID, etc.) car il n'est pas nécessaire de garder un shell supplémentaire sans rien faire". Mais dans ce cas, le script vise à réinventer la roue et à faire ce que le shell fait déjà assez bien, c'est-à-dire exécuter des commandes avec des arguments.


2
2017-10-20 19:23