Lorsque vous cherchez le chemin d'un exécutable ou de vérifier ce qui se passerait si vous entrez un nom de commande dans un shell Unix, il y a une pléthore de différents services publics ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
, etc.).
Nous entendons souvent que cela which
devrait être évité. Pourquoi? Que devrions-nous utiliser à la place?
shell
history
which
portability
Stéphane Chazelas
la source
la source
which
supposent un contexte de shell interactif. Cette question est étiquetée / portabilité. J'interprète donc la question dans ce contexte comme "quoi utiliser au lieu dewhich
trouver le premier exécutable d'un nom donné dans le$PATH
". La plupart des réponses et des raisons s'opposentwhich
au traitement des alias, des fonctions intégrées et des fonctions, qui dans la plupart des scripts shell portables du monde réel n'ont qu'un intérêt théorique. Les alias définis localement ne sont pas hérités lors de l'exécution d'un script shell (sauf si vous le sourcez.
).csh
(etwhich
reste uncsh
script sur la plupart des Unices commerciaux) lit~/.cshrc
quand il n'est pas interactif. C'est pourquoi vous remarquerez que les scripts csh commencent généralement par#! /bin/csh -f
.which
ne le fait pas parce qu'il vise à vous donner les alias, car il est conçu comme un outil pour les utilisateurs (interactifs) decsh
. POSIX shell utilisateurs ontcommand -v
.(t)csh
(ou ne vous dérange pas si elle ne vous donne pas le résultat correct), utiliseztype
oucommand -v
plutôt . Voir les réponses pour pourquoi .stat $(which ls)
est erroné pour plusieurs raisons (manquant--
, guillemets manquants), et pas seulement pour l'utilisation dewhich
). Vous utiliseriezstat -- "$(command -v ls)"
. Cela suppose qu’ills
s’agit bien d’une commande trouvée sur le système de fichiers (et non d’une fonction intégrée de votre shell ou de la fonction d’un alias).which
pourrait vous donner le mauvais chemin (pas le chemin que votre shell exécuterait si vous êtes entréls
) ou vous donner un alias tel que défini dans la configuration de certains autres shell ...which
implémentations ne vous donneraient même pas cels
qui pourrait être trouvé par une recherche de$PATH
(indépendamment de ce quils
peut être appelé dans votre shell).sh -c 'command -v ls'
, ouzsh -c 'rpm -q --whatprovides =ls'
sont plus susceptibles de vous donner la bonne réponse. Le point ici est quewhich
c'est un héritage brisé decsh
.Réponses:
Voici tout ce que vous n'auriez jamais pensé ne jamais vouloir savoir:
Sommaire
Pour obtenir le nom de fichier d’un exécutable dans un script shell de type Bourne (il existe quelques réserves; voir ci-dessous):
Pour savoir si une commande donnée existe:
À l'invite d'un shell interactif de type Bourne:
La
which
commande est un héritage brisé du C-Shell et il vaut mieux la laisser seule dans des coquilles à la Bourne.Cas d'utilisation
Il y a une différence entre rechercher ces informations dans le cadre d'un script ou de manière interactive à l'invite du shell.
À l’invite du shell, le cas d’utilisation typique est le suivant: cette commande se comporte étrangement, est-ce que j’utilise la bonne? Qu'est-ce qui s'est passé exactement quand j'ai tapé
mycmd
? Puis-je regarder plus loin ce que c'est?Dans ce cas, vous voulez savoir ce que fait votre shell lorsque vous appelez la commande sans l'invoquer.
Dans les scripts shell, cela a tendance à être très différent. Dans un script shell, il n'y a aucune raison pour laquelle vous voulez savoir où et quelle commande est si tout ce que vous voulez faire est de l'exécuter. Généralement, ce que vous voulez savoir, c'est le chemin de l'exécutable. Vous pouvez ainsi en extraire davantage d'informations (comme le chemin d'accès à un autre fichier par rapport à celui-ci ou lire des informations à partir du contenu du fichier exécutable situé sur ce chemin).
Vous voudrez peut-être connaître, de manière interactive, toutes les
my-cmd
commandes disponibles sur le système, rarement dans les scripts.La plupart des outils disponibles (comme c'est souvent le cas) ont été conçus pour être utilisés de manière interactive.
Histoire
Un peu d'histoire d'abord.
Les premiers shell Unix jusqu’à la fin des années 70 n’avaient aucune fonction ni pseudonyme. Seule la recherche traditionnelle des exécutables dans
$PATH
.csh
alias introduits autour de 1978 (maiscsh
a d' abord été publié en2BSD
en mai 1979), ainsi que le traitement d'un.cshrc
pour les utilisateurs de personnaliser la coque (chaque coquille, commecsh
lit.cshrc
même lorsqu'ils ne sont pas interactifs comme dans les scripts).Bien que le shell Bourne ait été publié pour la première fois dans Unix V7 plus tôt en 1979, le support des fonctions n’a été ajouté que beaucoup plus tard (1984 en SVR2), et de toute façon, il n’a jamais eu de
rc
fichier (.profile
c’est pour configurer votre environnement, pas le shell en tant que tel ).csh
est devenu beaucoup plus populaire que le shell Bourne car (même si sa syntaxe était bien pire que celle du shell Bourne), il ajoutait de nombreuses fonctionnalités plus pratiques et plus agréables pour une utilisation interactive.En
3BSD
(1980), unwhich
script csh a été ajouté pourcsh
aider les utilisateurs à identifier un exécutable. C’est un script à peine différent que vous pouvez trouver commewhich
sur de nombreux Unices commerciaux de nos jours (comme Solaris, HP / UX, AIX ou Tru64).Ce script lit l'utilisateur
~/.cshrc
(comme tous lescsh
scripts, à moins d'être appelé aveccsh -f
), et recherche le ou les noms de commande fournis dans la liste des alias et dans$path
(le tableau sur lequel on secsh
base$PATH
).Voilà,
which
c'est d'abord arrivé avec la coquille la plus populaire à l'époque (et elle l'csh
était toujours jusqu'au milieu des années 90), ce qui est la raison principale pour laquelle elle a été documentée dans des livres et est toujours largement utilisée.Notez que, même pour un
csh
utilisateur, cewhich
script csh ne vous donne pas nécessairement les bonnes informations. Il obtient les alias définis dans~/.cshrc
, pas ceux que vous avez définis ultérieurement à l'invite ou par exemple ensource
créant un autrecsh
fichier. (Bien que ce ne soit pas une bonne idée), ilsPATH
pourraient être redéfinis dans~/.cshrc
.L'exécution de cette
which
commande à partir d'un shell Bourne continuerait à rechercher les alias définis dans votre~/.cshrc
, mais si vous n'en avez pas, car vous n'utiliseriez pascsh
, vous obtiendrez probablement toujours la bonne réponse.Une fonctionnalité similaire n'a été ajoutée au shell Bourne qu'en 1984 dans SVR2 avec la
type
commande intégrée. Le fait qu'il soit intégré (par opposition à un script externe) signifie qu'il peut vous donner les bonnes informations (dans une certaine mesure) car il a accès aux éléments internes du shell.La
type
commande initialewhich
présentait un problème similaire à celui du script car elle ne renvoyait pas d'état de sortie en cas d'échec si la commande était introuvable. En outre, pour les exécutables, contrairement àwhich
cela, il génère quelque chose commels is /bin/ls
au lieu de tout/bin/ls
ce qui le rend moins facile à utiliser dans les scripts.Le shell Bourne de la version 8 de Unix (non publié à l’état sauvage) a
type
été renommé enwhatis
. Et le shell Plan9 (l'ancien successeur d'Unix)rc
(et ses dérivés commeakanga
etes
) ontwhatis
aussi.Le shell Korn (un sous-ensemble sur lequel la définition de POSIX sh est basée), développé au milieu des années 80 mais pas encore largement disponible avant 1988, a ajouté de nombreuses
csh
fonctionnalités (éditeur de ligne, alias ...) au-dessus du shell Bourne. . Il a ajouté sa propre fonctionwhence
intégrée (en plus detype
) qui a pris plusieurs options (-v
pour fournir unetype
sortie verbose semblable à celle-ci, et-p
ne rechercher que les exécutables (pas les alias / fonctions ...)).Par coïncidence avec la tourmente liée aux problèmes de droits d'auteur entre AT & T et Berkeley, quelques implémentations de shell de logiciels libres sont apparues à la fin des années 80 et au début des années 90. L’ensemble du shell Almquist (cendres, remplaçant du shell Bourne dans les BSD), l’implémentation dans le domaine public de ksh (pdksh)
bash
(parrainé par la FSF),zsh
est sorti entre 1989 et 1991.Ash, bien que censé remplacer le shell Bourne, n’a été
type
intégré que bien plus tard (dans NetBSD 1.3 et FreeBSD 2.3), bien qu’il en soit ainsihash -v
. OSF / 1/bin/sh
avait une fonctiontype
intégrée qui renvoyait toujours 0 à OSF / 1 v3.x.bash
n'a pas ajoutéwhence
mais ajouté une-p
option pourtype
imprimer le chemin (cetype -p
serait commewhence -p
) et-a
pour signaler toutes les commandes correspondantes.tcsh
faitwhich
builtin et a ajouté unewhere
commande agissant commebash
« stype -a
.zsh
a tous.Le
fish
shell (2005) a unetype
commande implémentée en tant que fonction.Le
which
script csh a quant à lui été supprimé de NetBSD (car il était intégré à tcsh et peu utilisé dans d’autres shells), et la fonctionnalité ajoutée àwhereis
(lorsqu’elle est appeléewhich
,whereis
se comporte commewhich
si elle ne cherchait que les exécutables$PATH
). Dans OpenBSD et FreeBSD,which
a également été remplacé par un script écrit en C qui ne recherche que les commandes$PATH
.Implémentations
Il existe des dizaines d'implémentations d'une
which
commande sur divers Unices avec une syntaxe et un comportement différents.Sous Linux (à côté de ceux intégrés dans
tcsh
etzsh
), nous trouvons plusieurs implémentations. Sur les systèmes Debian récents, par exemple, il s’agit d’un simple script shell POSIX qui cherche des commandes dans$PATH
.busybox
a également unewhich
commande.Il y en a une
GNU
which
qui est probablement la plus extravagante. Il essaie d’étendre ce que lewhich
script csh a fait à d’autres shells: vous pouvez lui indiquer quels sont vos alias et fonctions afin de vous donner une meilleure réponse (et je pense que certaines distributions Linux ont défini des alias mondiaux autour de cela pourbash
le faire) .zsh
a quelques opérateurs à développer dans le chemin des exécutables: l' opérateur de=
développement de nom de fichier et le:c
modificateur de développement d'historique (appliqué ici à la dilatation de paramètre ):zsh
, dans lezsh/parameters
module fait également la table de hachage de commande comme lecommands
tableau associatif:L'
whatis
utilitaire (à l'exception de celui de Unix V8 Bourne shell ou de Plan 9rc
/es
) n'est pas vraiment lié car il est destiné uniquement à la documentation (insère la base de données whatis, c'est-à-dire le synopsis de la page de manuel).whereis
a également été ajouté en3BSD
même temps quewhich
s'il était écritC
,csh
mais qu'il est utilisé pour rechercher en même temps l'exécutable, la page de manuel et le source, mais non sur l'environnement actuel. Encore une fois, cela répond à un besoin différent.Maintenant, sur le plan standard, POSIX spécifie les commandes
command -v
et-V
(qui étaient facultatives jusqu’à POSIX.2008). UNIX spécifie latype
commande (pas d'option). C'est tout (where
,which
,whence
ne sont pas spécifiées dans une norme)Jusqu'à une certaine version,
type
etcommand -v
étaient facultatifs dans la spécification Linux Standard Base, ce qui explique pourquoi, par exemple, certaines anciennes versions deposh
(bien qu'elles soient basées sur lespdksh
deux) n'en possédaient pas non plus.command -v
a également été ajouté à certaines implémentations du shell Bourne (comme sur Solaris).Statut aujourd'hui
Le statut actuel est le même
type
et ilcommand -v
est omniprésent dans tous les shells de type Bourne (bien que, comme l'a noté @jarno, notez l'avertissement / bogue en dehors dubash
mode POSIX ou de certains descendants du shell Almquist ci-dessous dans les commentaires).tcsh
est le seul shell où vous voudriez utiliserwhich
(car il n’y en a pastype
etwhich
est intégré).Dans les shells autres que
tcsh
etzsh
,which
peut vous indiquer le chemin de l’exécutable donné tant qu’il n’ya ni alias ni fonction du même nom dans aucun de nos fichiers~/.cshrc
,~/.bashrc
ni aucun fichier de démarrage du shell, et que vous ne définissez pas$PATH
dans votre~/.cshrc
. Si vous avez défini un alias ou une fonction, il peut vous en parler ou ne pas vous indiquer la mauvaise chose.Si vous voulez connaître toutes les commandes portant un nom donné, rien n’est portable. Vous utiliseriez
where
danstcsh
ouzsh
,type -a
dansbash
ouzsh
,whence -a
en ksh93 et dans d' autres coquilles, vous pouvez utilisertype
en combinaison avec cewhich -a
qui peut fonctionner.Recommandations
Obtenir le chemin d'accès à un exécutable
Maintenant, pour obtenir le chemin d’un exécutable dans un script, quelques mises en garde:
serait le moyen standard de le faire.
Il y a cependant quelques problèmes:
type
,which
,command -v
... tous utilisent des technologies heuristiques pour trouver le chemin. Ils parcourent les$PATH
composants en boucle et recherchent le premier fichier non répertoire pour lequel vous disposez d'une autorisation d'exécution. Cependant, selon le shell, quand il s'agit d'exécuter la commande, beaucoup d'entre eux (Bourne, AT & T ksh, zsh, ash ...) les exécuteront simplement dans l'ordre de$PATH
jusqu'à ce que l'execve
appel système ne revienne pas avec une erreur. . Par exemple, si$PATH
contient/foo:/bar
et que vous voulez exécuterls
, ils vont d'abord essayer de s'exécuter/foo/ls
ou si cela échoue/bar/ls
. Maintenant l'exécution de/foo/ls
peut échouer car vous n’avez pas le droit d’exécution, mais aussi pour de nombreuses autres raisons, comme l’exécutable n’est pas valide.command -v ls
signalerait/foo/ls
si vous avez une autorisation d'exécution pour/foo/ls
, mais l'exécutionls
peut en réalité s'exécuter/bar/ls
si ce/foo/ls
n'est pas un exécutable valide.foo
est une fonction ou un alias intégré,command -v foo
retournefoo
. Avec certains shells tels queash
,pdksh
ouzsh
, il peut également renvoyerfoo
si$PATH
inclut la chaîne vide et s'il existe unfoo
fichier exécutable dans le répertoire en cours. Dans certaines circonstances, vous devrez peut-être en tenir compte. Gardez à l’esprit, par exemple, que la liste des commandes intégrées varie en fonction de l’implémentation du shell (par exemple, ellemount
est parfois intégrée à busyboxsh
) etbash
peut , par exemple, obtenir des fonctions de l’environnement.$PATH
contient des composants de chemin relatif (généralement.
ou la chaîne vide qui font tous les deux référence au répertoire en cours mais peut être n'importe quoi), selon le shell,command -v cmd
peut ne pas générer un chemin absolu. Ainsi, le chemin que vous obtenez au moment où vous courezcommand -v
ne sera plus valable après votre passagecd
ailleurs./opt/ast/bin
(bien que cette voie exacte peut varier en fonction des différents systèmes , je crois) est en vous$PATH
, ksh93 mettra à la disposition quelques builtins supplémentaires (chmod
,cmp
,cat
...), maiscommand -v chmod
retournera/opt/ast/bin/chmod
même si ce chemin n » t existent.Déterminer si une commande existe
Pour savoir si une commande donnée existe de manière standard, vous pouvez faire:
Où on pourrait vouloir utiliser
which
(t)csh
En
csh
ettcsh
, tu n'as pas beaucoup de choix. Entcsh
, ça va commewhich
c'est construit. Danscsh
, ce sera lawhich
commande système , qui peut ne pas faire ce que vous voulez dans quelques cas.trouver des commandes uniquement dans certains coquillages
Un cas où il peut être judicieux d'utiliser
which
est si vous voulez connaître le chemin d'une commande, en ignorant shell potentiels builtins ou fonctionsbash
,csh
(nontcsh
),dash
ou desBourne
scripts shell, c'est - coquilles qui ne sont paswhence -p
(commeksh
ouzsh
) ,command -ev
(commeyash
),whatis -p
(rc
,akanga
) ou un élément intégréwhich
(commetcsh
ouzsh
) sur des systèmes oùwhich
est disponible et n'est pas lecsh
script.Si ces conditions sont remplies, alors:
vous donnera le chemin du premier
echo
dans$PATH
(sauf dans les cas d'angle), queecho
se trouve être également une commande du shell / alias / fonction ou non.Dans d'autres coquilles, vous préféreriez:
echo==echo
ouecho=$commands[echo]
ouecho=${${:-echo}:c}
echo=$(whence -p echo)
echo=$(command -ev echo)
echo=`whatis -p echo`
(méfiez-vous des chemins avec des espaces)set echo (type -fp echo)
Notez que si tout ce que vous voulez faire est d’ exécuter cette
echo
commande, vous n’avez pas à obtenir son chemin, vous pouvez simplement faire:Par exemple, avec
tcsh
, pour empêcher l’utilisationwhich
de la commande intégrée :quand vous avez besoin d'une commande externe
Vous pouvez également utiliser un autre cas lorsque vous
which
avez réellement besoin d' une commande externe. POSIX exige que toutes les fonctions intégrées dans le shell (commecommand
) soient également disponibles en tant que commandes externes, mais malheureusement, ce n'est pas le cascommand
sur de nombreux systèmes. Par exemple, il est rare de trouver unecommand
commande sur des systèmes d'exploitation basés sur Linux alors que la plupart d'entre eux ont unewhich
commande (bien que différentes avec des options et des comportements différents).Les cas dans lesquels vous souhaiterez peut-être une commande externe seraient ceux où vous exécuteriez une commande sans appeler un shell POSIX.
Les fonctions
system("some command line")
,popen()
... de C ou de divers langages invoquent un shell pour analyser cette ligne de commande;system("command -v my-cmd")
travaillez-y donc. Une exception à cela serait d'perl
optimiser le shell s'il ne voit aucun caractère spécial du shell (autre que l'espace). Cela s'applique également à son opérateur de backtick:L'ajout de ce qui
:;
précède forceperl
à y invoquer un shell. En utilisantwhich
, vous n'auriez pas à utiliser cette astuce.la source
which
est uncsh
script sur de nombreux Unices commerciaux. La raison en est historique, c'est pourquoi j'ai donné l'historique, afin que les gens comprennent d'où il vient, pourquoi les gens s'habituaient à l'utiliser et pourquoi, en fait, il n'y a aucune raison pour que vous l'utilisiez. Et oui, certaines personnes utilisent (t) csh. Tout le monde n'utilise pas encore Linuxwhich
, par opposition à des choses que vous pourriez essayer d'utiliserwhich
pour faire, l'historiquewhich
, les implémentations dewhich
, d'autres commandes pour effectuer des tâches connexes, ou des raisons d'utiliser réellementwhich
? Pourquoi les autres commandes sont-elles meilleures ? Que font-ils différemmentwhich
? Comment évitent-ils ses pièges? Cette réponse passe en réalité plus de mots sur les problèmes avec les alternatives que les problèmes avecwhich
.command -v
ne vérifie pas l'autorisation d'exécution, du moins si vous l'appelez par un argument de nom de fichier pur sans chemin. J'ai testé par tiret 0.5.8 et GNU bash 4.3.48.touch /usr/bin/mytestfile
de l'exécutercommand -v mytestfile
, il donnera le chemin (alors que cewhich mytestfile
n'est pas le cas).bash
se contentera d’un fichier non-exécutable s’il ne trouve pas de fichier exécutable, c’est donc "OK" (même si en pratique on préféreraitcommand -v
/type
renvoyer une erreur) car c’est la commande qu’il essaierait d’exécuter lors de l’exécutionmytestfile
, mais ledash
comportement est buggy, comme si il y avait un non-exécutablecmd
avant un exécutable,command -v
renvoie le non-exécutable lors de l'exécutioncmd
exécuterait l'exécutable (le mauvais est également haché). FreeBSDsh
(également basé surash
) a le même bogue. zsh, yash, ksh, mksh, bash comme sh sont OK.Les raisons pour lesquelles on peut ne pas vouloir utiliser
which
ont déjà été expliquées, mais voici quelques exemples sur quelques systèmes où lawhich
défaillance a effectivement eu lieu.Sur les obus Bourne-like, nous comparons le résultat de (
which
avec le résultat detype
(type
étant un shell intégré, il est censé être la vérité sur le terrain, car il nous dit comment invoquer une commande).Beaucoup de cas sont des cas de coin , mais gardez à l'esprit que
which
/type
sont souvent utilisés dans des cas de coin (pour trouver la réponse à un comportement inattendu du type: pourquoi est-ce que cette commande se comporte comme ça, quelle est la personne que j'appelle? ).La plupart des systèmes, la plupart des coques de type Bourne: fonctions
Le cas le plus évident concerne les fonctions:
La raison en est que
which
seuls les rapports concernant les exécutables, et parfois les alias (bien que pas toujours ceux de votre shell), pas les fonctions.La page de manuel GNU a un exemple cassé (car ils ont oublié de citer
$@
) sur son utilisation pour signaler des fonctions, mais tout comme pour les alias, car elle n’implémente pas d’analyseur de syntaxe de shell, elle est facilement trompée:La plupart des systèmes, la plupart des coques de type Bourne: Intégrés
Un autre cas est évidente builtins ou des mots - clés, comme
which
étant une commande externe n'a aucun moyen de savoir qui builtins votre shell ont (et quelques coquilles commezsh
,bash
ouksh
peut charger dynamiquement builtins):(cela ne s'applique pas à l'
zsh
endroit oùwhich
est intégré)Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5.1 et de nombreux autres:
C'est parce que sur la plupart des systèmes Unix commerciaux,
which
(comme dans la mise en œuvre originale sur 3BSD) est uncsh
script qui lit~/.cshrc
. Les alias qu'il signalera sont ceux définis ici, quels que soient les alias que vous avez définis et quel que soit le shell utilisé.Sous HP / UX ou Tru64:
(les versions de Solaris et AIX ont résolu ce problème en enregistrant
$path
avant de lire~/.cshrc
et de le restaurer avant de rechercher la ou les commandes)Ou:
(bien sûr, en tant que
csh
script, vous ne pouvez pas vous attendre à ce qu'il fonctionne avec des arguments contenant des espaces ...)CentOS 6.4, bash
Sur ce système, un alias défini à l’échelle du système enveloppe la
which
commande GNU .La sortie est fausse parce que
which
lit la sortie debash
« salias
mais ne sait pas comment l'analyser correctement et utilise heuristiques (un alias par ligne, recherche la première commande trouvée après|
,;
,&
...)La pire chose sur CentOS est que sa commande intégrée soit
zsh
parfaitement fine,which
mais CentOS a réussi à la rompre en la remplaçant par un alias non fonctionnel de GNUwhich
.Debian 7.0, ksh93:
(bien que cela s'applique à la plupart des systèmes avec beaucoup de coques)
Sur Debian,
/bin/which
c'est un/bin/sh
script. Dans mon cas,sh
êtredash
mais c'est pareil quand c'estbash
.Un non défini
PATH
ne consiste pas à désactiver laPATH
recherche, mais à utiliser le PATH par défaut du système qui, malheureusement, sur Debian, personne n’accepte (dash
etbash
a/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
,zsh
a/bin:/usr/bin:/usr/ucb:/usr/local/bin
,ksh93
a/bin:/usr/bin
,mksh
a/usr/bin:/bin
($(getconf PATH)
),execvp()
(comme dansenv
) a:/bin:/usr/bin
(oui, regarde en premier dans le répertoire courant! )).C’est pourquoi
which
on se trompe ci-dessus car il utilisedash
la valeur par défautPATH
qui est différente de celleksh93
deCe n'est pas mieux avec GNU
which
qui rapporte:(il est intéressant de noter qu’il existe effectivement
/usr/local/bin/which
sur mon système unakanga
script qui est venu avecakanga
(unrc
dérivé du shell où la valeur par défautPATH
est/usr/ucb:/usr/bin:/bin:.
))bash, n’importe quel système:
Celui auquel Chris fait référence dans sa réponse :
Aussi après avoir appelé
hash
manuellement:Maintenant, un cas où
which
et parfoistype
échouer:Maintenant, avec quelques coquilles:
Avec les autres:
Ni peut
which
nitype
savoir à l'avance quib/foo
ne peut pas être exécuté. Quelques coquilles commebash
,ksh
ouyash
, lors de l' appelfoo
va essayer en effet d'exécuterb/foo
et signaler une erreur, tandis que d' autres (commezsh
,ash
,csh
,Bourne
,tcsh
) se dérouleraa/foo
sur l'échec de l'execve()
appel système surb/foo
.la source
mksh
utilise en réalité quelque chose de différent pour la valeur par défaut$PATH
: premièrement, la constante de compilation du système d'exploitation_PATH_DEFPATH
est utilisée (le plus souvent sur les BSD), ensuite,confstr(_CS_PATH, …)
est utilisée (POSIX), et si les deux n'existent pas ou échouent, elle/bin:/usr/bin:/sbin:/usr/sbin
est utilisée.ls
est une fonction qu’elle utilisels
depuis PATH. Etwhich
est bien de vous dire lequel est utilisé/usr/bin/ls
ou/usr/local/bin/ls
. Je ne vois pas "Pourquoi ne pas utiliser lequel" ....which ls
me donnera/bin/ls
indépendamment du fait que lals
fonction appelle/bin/ls
ou/opt/gnu/bin/ls
oudir
ou rien du tout. IOW,which
(celui dont les implémentations, IMMV) donne quelque chose de hors de proposls
est une fonction. Je sais que mals
fonction appellels
dePATH
. Maintenant,which
me dit où se trouve le fichier. Vous ne voyez qu'un seul cas d'utilisation: "Que ferait mon shell avec cette commande". Pour ce cas d'utilisationwhich
est faux, correct. Mais il existe d'autres cas d'utilisation où (GNU)which
est exactement la bonne chose.which
implémentation. Certains vous diront que c'est un alias (si vous avez un alias configuré ou s'il y en a un~/.cshrc
dans votre maison qui en possède un), certains vous donneront un chemin, mais le mauvais dans certaines conditions.sh -c 'command -v ls'
Bien que pas parfait, vous aurez toujours plus de chances de vous donner la bonne réponse à cette exigence différente (et également standard).Une chose qui (d'après mon rapide survol) il semble que Stéphane ne l'ait pas mentionné, c'est qu'elle
which
n'a aucune idée de la table de hachage de votre shell. Cela a pour effet que le résultat obtenu risque de ne pas être représentatif de ce qui est réellement exécuté, ce qui le rend inefficace pour le débogage.la source
Dans l’esprit UNIX: Faites que chaque programme fasse bien une chose.
Si le but est de répondre: quel exécutable existe avec ce nom?
Le programme exécutable fourni avec les systèmes Debian est une bonne réponse. Le qui fourni avec csh inclus des alias, c'est une source de problèmes. Les objectifs fournis par certains shells en tant que composants internes ont un objectif différent. Utilisez cet exécutable ou utilisez le script fourni à la fin de cette réponse.
Si ce script est utilisé, sa réponse est propre, simple et utile.
Cet objectif correspond à la première phrase de votre question:
Si vous avez un système qui ne contient pas d'exécutable appelé (la plupart des systèmes linux en ont un), vous pouvez en créer un
~/bin/which
auparavant/bin/
dans PATH afin que les exécutables personnels remplacent ceux du système, comme celui qui se trouve au bas de cet article:Ce exécutable liste (par défaut) tous les executables trouvés dans le PATH. Si seul le premier est requis, l'option
-f
est disponible.À ce stade, nous tombons sur un objectif différent:
ce que le shell exécutera (après l'analyse)
Cela vient de votre deuxième phrase:
Ce deuxième sujet tente de trouver une bonne réponse à une question assez difficile à répondre. Les coquillages ont des points de vue divergents, des cas en coin et (au minimum) des interprétations différentes. Ajoutant à cela:
Et bien sûr, toutes les tentatives correspondent à cet objectif.
Éviter lequel?
Je me demande: pourquoi cela devrait-il être dit si cela
which
fonctionne (au moins dans debian)?Dans l’esprit UNIX: Faites que chaque programme fasse bien une chose.
Le programme externe
which
fait une chose: recherchez le premier exécutable sur le chemin qui porte le même nom que le nom de la commande . Et le fait raisonnablement bien.Je ne connais aucun autre programme ou utilitaire qui réponde à cette question de manière plus fondamentale. En tant que tel, il est utile et pourrait être utilisé en cas de besoin.
L’alternative la plus proche semble être
command -pv commandName
:, mais cela rapportera également des noms intégrés et des alias. Pas la même réponse.Bien sûr,
which
est limité, il ne répond pas à toutes les questions, aucun outil ne peut le faire (enfin, pas encore ...). Mais il est utile lorsqu’il est utilisé pour répondre à la question à laquelle il a été conçu (celui ci-dessus). Un peu commeed
était limité et puissed
est apparu (ouvi
/vim
). Ou comme siawk
c'était limité et que Perl est apparu et étendu. Pourtant,ed
,sed
et / ouawk
ont des cas d'utilisation spécifiques oùvim
ouperl
sont pas les meilleurs outils.Probablement parce que les
which
réponses ne représentent qu'une partie de la question qu'un utilisateur du shell pourrait demander:Qu'est-ce qui est en cours d'exécution lorsque je tape un nom de commande?
Externe qui
Ce qui devrait être disponible (dans de nombreux systèmes) en tant qu'exécutable externe.
Le seul moyen sûr d'appeler cet outil externe est d'utiliser env pour sortir du shell, puis d'appeler
which
(ce qui fonctionne dans tous les shells):Ou utilisez le chemin complet vers
which
(qui peut varier selon les systèmes):Pourquoi est-ce
hack
nécessaire? Parce que certains coquillages (spécialement zsh) cachentwhich
:Être un outil externe (comme
env
) explique parfaitement pourquoi il ne rapportera pas d'informations internes au shell. Comme des alias, des fonctions, des éléments intégrés, des éléments spéciaux, des variables shell (non exportées), etc.:La sortie vide de
ll
(un alias commun pourll='ls -l'
) indique qu'illl
n'est pas lié à un programme exécutable, ou du moins qu'il n'y a pas de fichier exécutable nomméll
dans le chemin PATH. L'utilisation dell
devrait appeler autre chose, dans ce cas, un alias:type
etcommand
Les commandes
type
etcommand -v
sont demandées par POSIX. On devrait s’attendre à ce qu’ils travaillent dans la plupart des coquillages, et ils le font, sauf dans csh, tcsh, fish et rc.Les deux commandes pourraient être utilisées pour fournir un autre point de vue de la commande à exécuter.
whence
,where
,whereis
,whatis
,hash
Ensuite, il y a
whence
,where
,whereis
,whatis
,hash
, et quelques autres. Toutes les réponses différentes à des questions similaires. Tous travaillent de différentes manières dans différents coquillages. Probablement,whence
est le plus commun aprèstype
. Les autres sont des solutions spéciales qui répondent à la même question de différentes manières.Probablement d'
which
abord savoir s'il existe un fichier exécutable par le nom du commandName , puistype
etcommand
puis, si le commandName n'a pas encore été trouvée:whence
,where
,whereis
,whatis
,hash
dans cet ordre.Script shell pour fournir un
which
exécutable.la source
Je n'ai jamais entendu ça. Veuillez fournir des exemples spécifiques. Je m'inquiéterais de votre distribution Linux et de vos progiciels installés, car c'est de là que ça
which
vient!SLES 11.4 x86-64
dans tcsh version 6.18.01:
dans les versions 3.2-147 de bash:
which
fait partie d' util-linux, un paquet standard distribué par l'organisation du noyau Linux à utiliser avec le système d'exploitation Linux. Il fournit également ces autres fichiersmon
util-linux
est la version 2.19. Les notes de version se retrouvent facilement dans la v2.13 du 28 août 2007. Pas sûr du but ou de l’objectif de ceci, il n’a certainement pas été répondu 333 fois plus longtemps.la source
which -v
montre, il s’agit de GNU (l’extravagant mentionné dans l’autre réponse et n’est en aucun cas spécifique à Linux), pas util-linux pour lequel AFAIK n’a jamais inclus d’which
utilitaire. util-linux 2.19 est à partir de 2011, GNU qui est à 2,19 est de 2008.