J'ai défini une fonction shell (appelons-la clock
), que je veux utiliser comme wrapper pour une autre commande, similaire à la time
fonction, par exemple clock ls -R
.
Ma fonction shell effectue certaines tâches, puis se termine par exec "$@"
.
Je voudrais que cette fonction fonctionne même avec les commandes internes du shell, par exemple clock time ls -R
devrait produire le résultat de la commande time
intégrée, et non l' /usr/bin/time
exécutable. Mais exec
finit toujours par exécuter la commande à la place.
Comment puis-je faire en sorte que ma fonction Bash fonctionne comme un wrapper qui accepte également les arguments intégrés au shell comme arguments?
Edit : je viens d'apprendre que ce time
n'est pas un Bash intégré, mais un mot réservé spécial lié aux pipelines. Je suis toujours intéressé par une solution pour les intégrés même si cela ne fonctionne pas time
, mais une solution plus générale serait encore meilleure.
la source
exec bash -c \' "$@" \'
. À moins que votre commande dans le premier paramètre ne soit reconnue comme un script shell, elle sera interprétée comme un binaire à exécuter directement. Alternativement, et plus simplement, il vous suffit de rater leexec
et d'appeler"@"
depuis votre shell d'origine.Réponses:
Vous avez défini une fonction bash. Vous êtes donc déjà dans un shell bash lorsque vous appelez cette fonction. Donc, cette fonction pourrait alors simplement ressembler à:
Cette fonction peut être invoquée avec des commandes bash, des mots réservés spéciaux, des commandes, d'autres fonctions définies:
Un alias:
Un bash intégré:
Une autre fonction:
Un exécutable:
la source
$@
etexec $@
, si je sais que j'exécute une commande réelle?exec
, la commande remplace le shell. Il n'y a donc plus de commandes intégrées, d'alias, de mots réservés spéciaux, de mots définis, car l'exécutable est exécuté via un appel systèmeexecve()
. Ce syscall attend un fichier exécutable.exec $0
un seul processus, alors$@
qu'il en existe encore deux.$@
le shell en cours d'exécution est parent et la commande est un processus enfant. Mais lorsque vous souhaitez utiliser des commandes internes, des alias, etc., vous devez conserver le shell. Ou commencez-en un nouveau.La seule façon de lancer un shell intégré ou un mot clé shell est de lancer un nouveau shell car exec "remplace le shell par la commande donnée". Vous devez remplacer votre dernière ligne par:
Cela fonctionne à la fois avec les mots intégrés et les mots réservés; Le principe est le même.
la source
Si l'encapsuleur doit insérer du code avant la commande donnée, un alias fonctionnera car ils sont développés à un stade très précoce:
Les alias sont presque littéralement insérés à la place du mot aliasé, donc la fin
;
est importante - elle seclock time foo
développe jusqu'àdo this; do that; time foo
.Vous pouvez en abuser pour créer des alias magiques qui contournent même les guillemets.
Pour insérer du code après une commande, vous pouvez utiliser le hook "DEBUG".
Plus précisément:
Le hook s'exécute toujours avant la commande, mais au retour,
false
il indique à bash d'annuler l'exécution (car le hook l'a déjà exécuté via eval).Comme autre exemple, vous pouvez l'utiliser comme alias
command please
poursudo command
:la source
La seule solution que j'ai pu trouver jusqu'à présent serait d'effectuer une analyse de cas pour distinguer si le premier argument est une commande, intégrée ou un mot clé, et échouer dans le dernier cas:
Il ne gère pas
time
, cependant, donc il pourrait y avoir une meilleure solution (et plus concise).la source