Pour faire court: je voudrais suivre la façon dont certains exécutables sont appelés pour suivre certains comportements du système. Disons que j'ai un exécutable:
/usr/bin/do_stuff
Et il est en fait appelé par un certain nombre de noms différents via un lien symbolique:
/usr/bin/make_tea -> /usr/bin/do_stuff
/usr/bin/make_coffee -> /usr/bin/do_stuff
etc. De toute évidence, do_stuff
va utiliser le premier argument qu'il reçoit pour déterminer quelle action est réellement prise, et le reste des arguments sera traité à la lumière de cela.
Je voudrais enregistrer chaque appel à /usr/bin/do_stuff
(et la liste complète des arguments). S'il n'y avait pas de liens symboliques, je voudrais simplement passer do_stuff
à do_stuff_real
et d' écrire un script
#!/bin/sh
echo "$0 $@" >> logfile
/usr/bin/do_stuff_real "$@"
Cependant, comme je sais qu'il examinera le nom par lequel il est appelé, cela ne fonctionnera pas. Comment peut-on écrire un script pour atteindre le même résultat tout en transmettant le do_stuff
bon «nom utilisé exécutable»?
Pour mémoire, pour éviter les réponses sur ces lignes:
- Je sais que je peux le faire en C (en utilisant execve), mais ce serait beaucoup plus facile si je pouvais, dans ce cas, simplement utiliser un script shell.
- Je ne peux pas simplement remplacer
do_stuff
par un programme de journalisation.
la source
sh
, vous pouvez utiliser à lamybase=${0##*/}
place du nom de base.basename
invocation comme çabasename -- foo.bar
ne m'est pas familière, et sur le système Linux surfoo.bar
lequel je l'ai testée produit le résultat qui casserait le script. Êtes-vous sûr que c'est une méthode courante?basename -- foo.bar
renvoiefoo.bar
,basename -- --foo--/bar
retournebar
comme prévu.basename "$foo"
ne fonctionne que si vous pouvez garantir$foo
ne commence pas par un-
. La syntaxe générale pour appeler une commande avec des arguments arbitraires estcmd -x -y -- "$argument"
.cmd "$argument"
est faux, sauf si vous voulez direcmd "$option_or_arg"
. Maintenant, certaines commandes (y compris certaines implémentations historiques debasename
) ne prennent pas en charge--
, vous devrez donc parfois choisir entre la portabilité et la fiabilité.Vous pouvez utiliser
exec -a
(que l'on trouve dansbash
,ksh93
,zsh
,mksh
,yash
mais pas encore Posix) qui est utilisé pour spécifier uneargv[0]
à une commande en cours d' exécution:Notez que ce
$0
n'est pas ceargv[0]
que la commande reçoit. C'est le chemin du script tel que transmis àexecve()
(et qui est transmis comme argumentbash
), mais cela est probablement suffisant pour votre objectif.Par exemple, si a
make_tea
été invoqué comme:Comme le ferait généralement un shell lors de l'appel de la commande par son nom (en recherchant l'exécutable dans
$PATH
), l'encapsuleur devrait:Ce n'est pas:
mais c'est assez bon car on
do_stuff_real
sait que c'est fait pour faire du thé.Là où ce serait un problème, c'est si a
do_stuff
été invoqué comme:car cela se traduirait par:
Cela ne se produirait pas pendant les opérations normales, mais notez que notre wrapper fait quelque chose comme ça.
Sur la plupart des systèmes, le
argv[0]
tel que transmis au script est perdu une fois que l'interpréteur (ici/bin/bash
) est exécuté ( leargv[0]
de l'interpréteur sur la plupart des systèmes est le chemin indiqué sur la ligne de coup ) donc il n'y a rien qu'un script shell puisse faire à ce sujet.Si vous vouliez passer le
argv[0]
long, vous auriez besoin de compiler un exécutable. Quelque chose comme:la source
perl
oupython
si disponible. Les anciennes versions dezsh
ne prenaient pas en chargeexec -a
, mais vous pouvez toujours utiliser à laARGV0=the-argv-0 cmd args
place.zsh
(bien que maintenant vous ayez clairement indiqué que vous ne l'avez pas fait) mais qu'il était trop ancien, vous pourriez toujours l'utiliserARGV0
.