Les programmes Unix / Linux typiques acceptent les entrées de ligne de commande sous la forme d'un nombre d'arguments ( int argc
) et d'un vecteur d'arguments ( char *argv[]
). Le premier élément argv
est le nom du programme, suivi des arguments réels.
Pourquoi le nom du programme est-il passé à l'exécutable en tant qu'argument? Existe-t-il des exemples de programmes utilisant leur propre nom (peut-être une sorte de exec
situation)?
command-line
c
arguments
Shrikant Giridhar
la source
la source
sh
est un lien symbolique versdash
. Ils se comportent différemment, lorsqu'ils sont appelés en tantsh
quedash
busybox
(commun sur les disques de secours et autres), alors à peu près tout (cp, mv, rm, ls, ...) est un lien symbolique vers busybox.gcc
,bash
,gunzip
, la plupart du reste du système d' exploitation ...), comme Linux est que le noyau.Réponses:
Pour commencer, notez que ce
argv[0]
n'est pas nécessairement le nom du programme. C'est ce que l'appelant met dansargv[0]
l'execve
appel système (par exemple, voir cette question sur le dépassement de capacité de la pile ). (Toutes les autres variantes deexec
ne sont pas des appels système, mais des interfaces avecexecve
.)Supposons, par exemple, ce qui suit (utiliser
execl
):/var/tmp/mybackdoor
est ce qui est exécuté maisargv[0]
réglé surtop
, et c’est ce queps
ou (le réel)top
afficherait. Voir cette réponse sur U & L SE pour plus d'informations.Mettre tout cela de côté: Avant l’avènement de systèmes de fichiers sophistiqués
/proc
,argv[0]
c’était le seul moyen pour un processus d’en savoir plus sur son propre nom. Qu'est-ce que ce serait bon?la source
bunzip2
,bzcat
etbzip2
, pour lesquels les deux premiers sont des liens symboliques vers le troisième.zcat
n'est pas un lien symbolique. Ils semblent éviter les inconvénients de cette technique en utilisant plutôt un script shell. Mais ils ne parviennent pas à imprimer une--help
sortie complète car quelqu'un qui a ajouté des options à gzip a également oublié de maintenir zcat.gunzip
est une exception historique.argv[0]
leur utilisation / aide au lieu de coder en dur leur nom. Certains dans leur intégralité, d'autres simplement le nom de base.Beaucoup:
argv[0]
estsh
. Il fonctionne comme un shell de connexion quandargv[0]
commence par-
.vi
,view
,evim
,eview
,ex
,vimdiff
, etc.shutdown
,reboot
, etc. sont des liens symboliques àsystemctl
.la source
sendmail
etmail
. Chaque MTA unix est livré avec un lien symbolique pour ces deux commandes et est conçu pour émuler le comportement de l'original lorsqu'il est appelé en tant que tel, ce qui signifie que tout programme unix devant envoyer un courrier sait exactement comment le faire.test
et[
: lorsque vous appelez le premier, il gère une erreur si le dernier argument est]
. (Sur Debian stable, ces commandes sont deux programmes différents, mais les versions précédentes et MacO utilisent toujours le même programme). Ettex
,latex
et ainsi de suite: le binaire est le même, mais en regardant la façon dont il a été appelé, il choisir la bonne configuration fichier.init
est similaire.[
considère que c'est une erreur si le dernier argument n'est pas]
.Historiquement, il
argv
n’ya qu’un tableau de pointeurs sur les "mots" de la ligne de commande, il est donc logique de commencer par le premier "mot", qui se trouve être le nom du programme.Et il y a beaucoup de programmes qui se comportent différemment selon le nom utilisé pour les appeler, vous pouvez donc simplement créer différents liens avec eux et obtenir différentes "commandes". L'exemple le plus extrême auquel je puisse penser est busybox , qui agit comme plusieurs douzaines de "commandes" différentes en fonction de la manière dont elle est appelée .
Edit : Références pour Unix 1ère édition, comme demandé
On peut voir par exemple de la fonction principale de
cc
celaargc
etargv
ont déjà été utilisés. Le shell copie les arguments à l'parbuf
intérieur de lanewarg
partie de la boucle, tout en traitant la commande elle-même de la même manière que les arguments. (Bien entendu, il n'exécutera plus tard que le premier argument, qui est le nom de la commande). On dirait que lesexecv
parents n'existaient pas alors.la source
exec
prend le nom de la commande à exécuter et un tableau de pointeurs de caractères à zéro (mieux visible à minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , oùexec
prend références à l'étiquette 2 et étiquette 1, et à l'étiquette2:
apparaîtetc/init\0
, et à l'étiquette1:
apparaît une référence à l'étiquette 2, et un zéro final), qui est fondamentalement ce quiexecve
fait aujourd'hui moinsenvp
.execv
etexecl
existent "depuis toujours" (c'est-à-dire depuis le début jusqu'au milieu des années 1970) -execv
était un appel système etexecl
une fonction de bibliothèque qui l'appelait.execve
n'existait pas alors parce que l'environnement n'existait pas alors. Les autres membres de la famille ont été ajoutés plus tard.execv
dans la source v1 que j'ai liée? Juste curieux.Cas d'utilisation:
Vous pouvez utiliser le nom du programme pour changer le comportement du programme .
Par exemple, vous pouvez créer des liens symboliques vers le binaire actuel.
Un exemple célèbre où cette technique est utilisée est le projet busybox qui n’installe qu’un seul binaire et de nombreux liens symboliques. (ls, cp, mv, etc.). Ils le font pour économiser de l'espace de stockage car leurs cibles sont de petits périphériques intégrés.
Ceci est aussi utilisé
setarch
depuis util-linux:Ici, ils utilisent essentiellement cette technique pour éviter de nombreux fichiers sources en double ou pour que les sources soient toujours plus lisibles.
Un autre cas d'utilisation serait un programme devant charger certains modules ou certaines données au moment de l'exécution. Avoir le chemin du programme vous permet de charger des modules à partir d'un chemin relatif à l'emplacement du programme .
En outre, de nombreux programmes impriment des messages d'erreur, notamment le nom du programme .
Pourquoi :
man 3p execve
):Notez que la norme C dit "nom du programme" et non "nom de fichier".
la source
En plus des programmes modifiant leur comportement en fonction de la manière dont ils ont été appelés, je trouve
argv[0]
utile d'imprimer l'utilisation d'un programme, comme suit:Cela fait que le message d'utilisation utilise toujours le nom par lequel il a été appelé. Si le programme est renommé, son message d'utilisation change avec lui. Il comprend même le nom du chemin avec lequel il a été appelé:
C'est une bonne idée, en particulier pour les petits outils / scripts spéciaux qui pourraient vivre partout.
Cela semble également être une pratique courante dans les outils GNU, voir
ls
par exemple:la source
On exécute le typage du programme:
program_name0 arg1 arg2 arg3 ...
.Donc, le shell devrait déjà diviser le jeton, et le premier jeton est déjà le nom du programme. Et BTW donc il y a les mêmes indices côté programme et côté shell.
Je pense que c'était juste une astuce de commodité (au tout début), et, comme vous le voyez dans d'autres réponses, c'était aussi très pratique, cette tradition a donc été maintenue et définie en tant qu'API.
la source
Fondamentalement, argv inclut le nom du programme afin que vous puissiez écrire des messages d'erreur tels que
prgm: file: No such file or directory
, qui seraient implémentés avec quelque chose comme ceci:la source
Ce programme est un autre exemple d'application de ce programme, qui se remplace par ... lui-même, jusqu'à ce que vous tapiez quelque chose qui ne l'est pas
y
.De toute évidence, il s’agit d’un exemple artificiel, mais intéressant, mais je pense que cela peut avoir de véritables utilisations - par exemple, un binaire à mise à jour automatique, qui réécrit son propre espace mémoire avec une nouvelle version de lui-même qu’il a téléchargée ou modifiée.
Exemple:
Source, et quelques informations supplémentaires .
la source
Le chemin d'accès au programme est
argv[0]
afin que le programme puisse extraire les fichiers de configuration, etc. de son répertoire d'installation.Ce serait impossible sans
argv[0]
.la source
(char *path_to_program, char **argv, int argc)
par exemple~/.<program>
,/etc/<program
,$XDG_CONFIG_HOME
) et prendre un paramètre pour le modifier ou une option de compilation qui fait cuire dans une constante binaire.ccache se comporte de cette manière pour imiter différents appels aux fichiers binaires du compilateur. ccache est un cache de compilation - l’important n’est jamais de compiler deux fois le même code source, mais plutôt de renvoyer le code objet à partir du cache si possible.
Dans la page de manuel de ccache , "il existe deux manières d’utiliser ccache. Vous pouvez préfixer ccache de vos commandes de compilation ou laisser ccache se masquerade en tant que compilateur en créant un lien symbolique (nommé en tant que compilateur) vers ccache. La première méthode est plus pratique si vous voulez simplement essayer ccache ou si vous souhaitez l’utiliser pour certains projets spécifiques. La deuxième méthode est plus utile lorsque vous souhaitez utiliser ccache pour toutes vos compilations. "
La méthode des liens symboliques implique l'exécution de ces commandes:
... qui a pour effet de permettre à ccache de prendre toutes les commandes qui auraient sinon été transmises aux compilateurs, permettant ainsi à ccache de renvoyer un fichier en cache ou de transmettre la commande au compilateur réel.
la source