Lors de la recherche du chemin vers un exécutable ou de la vérification de ce qui se passerait si vous saisissiez un nom de commande dans un shell Unix, il existe « une pléthore dutilitaires différents ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
, etc).
On entend souvent dire que which
doit être évité. Pourquoi? Que devrions-nous utiliser à la place?
Commentaires
Réponse
Voici tout ce que vous nauriez jamais pensé ne pas vouloir savoir à ce sujet:
Résumé
Pour obtenir le chemin dun exécutable dans un script shell de type Bourne (il y a quelques mises en garde; voir ci-dessous):
ls=$(command -v ls)
Pour savoir si une commande donnée existe:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
À linvite dun shell interactif de type Bourne:
type ls
Le La commande which
est un héritage brisé du C-Shell et il vaut mieux la laisser seule dans les shells de type Bourne.
Cas dutilisation
Là « une distinction entre la recherche de ces informations dans le cadre dun script ou de manière interactive à linvite du shell.
À linvite du shell, le cas dutilisation typique est: cette commande se comporte de façon étrange, est-ce que jutilise le la bonne? Que sest-il passé exactement lorsque jai tapé mycmd
? Puis-je regarder plus loin ce que cest?
Dans ce cas, vous voulez savoir ce que fait votre shell lorsque vous appelez la commande sans réellement appeler la commande.
Dans les scripts shell, cela a tendance à être assez différent. Dans un script shell, il ny a aucune raison pour laquelle vous voulez savoir où ou ce quest une commande si tout ce que vous voulez faire est de lexécuter. Généralement, ce que vous voulez savoir est le chemin de lexécutable, afin que vous puissiez en obtenir plus dinformations (comme le chemin vers un autre fichier relatif à celui-ci, ou lire des informations à partir du contenu du fichier exécutable à ce chemin).
De manière interactive, vous voudrez peut-être connaître toutes les commandes my-cmd
disponibles sur le système, dans des scripts, rarement.
La plupart des outils disponibles (comme cest souvent le cas) ont été conçus pour être utilisés de manière interactive.
Historique
Un peu dhistoire dabord.
Les premiers shells Unix jusquà la fin des années 70 navaient ni fonctions ni alias. Uniquement la recherche traditionnelle dexécutables dans $PATH
. csh
a introduit des alias vers 1978 (bien que csh
ait été publié pour la première fois en 2BSD
, en mai 1979), ainsi que le traitement dun .cshrc
permettant aux utilisateurs de personnaliser le shell (chaque shell, comme csh
, lit .cshrc
même sil nest pas interactif comme dans les scripts).
Alors que le shell Bourne a été publié pour la première fois dans Unix V7 plus tôt en 1979, le support des fonctions na été que beaucoup ajouté plus tard (1984 dans SVR2), et de toute façon, il na jamais eu de fichier rc
(le .profile
sert à configurer votre environnement, pas le shell en soi ).
csh
est devenu beaucoup plus populaire que le shell Bourne car (même sil avait une syntaxe terriblement pire que le Bourne shell), il ajoutait beaucoup de fonctionnalités plus pratiques et plus intéressantes pour une utilisation interactive.
Dans 3BSD
(1980), un which
script csh a été ajouté pour les utilisateurs de csh
pour aider à identifier un exécutable, et cest un script à peine différent que vous pouvez trouver comme which
sur de nombreux Unices commerciaux de nos jours (comme Solaris, HP / UX, AIX ou Tru64).
Ce script lit lutilisateur » s ~/.cshrc
(comme tous les scripts csh
sauf sils sont appelés avec csh -f
), et recherche le (s) nom (s) de commande fourni (s) dans la liste des alias et dans $path
(le tableau que csh
maintient en fonction de $PATH
).
Et voilà: which
est arrivé en premier pour le shell le plus populaire de lépoque (et csh
était toujours populaire jusquau milieu- 90s), qui est la principale raison pour laquelle il a été documenté dans des livres et est encore largement utilisé.
Notez que, même pour un utilisateur csh
, que which
Le script csh ne vous donne pas forcément la bonne information. Il obtient les alias définis dans ~/.cshrc
, pas ceux que vous avez peut-être définis plus tard à linvite ou par exemple par source
un autre csh
et (bien que ce ne soit pas une bonne idée), PATH
pourrait être redéfini dans ~/.cshrc
.
Lexécution de cette commande which
à partir dun shell Bourne chercherait toujours les alias définis dans votre ~/.cshrc
, mais si vous nen avez pas parce que vous nutilisez pas csh
, vous obtiendrez probablement la bonne réponse.
Une fonctionnalité similaire na pas été ajoutée à le Bourne shell jusquen 1984 en SVR2 avec la commande intégrée type
. Le fait quil soit intégré (par opposition à un script externe) signifie quil peut vous donner les bonnes informations (dans une certaine mesure) car il a accès aux éléments internes du shell.
La commande initiale type
a souffert dun problème similaire à celui du script which
en ce sens quelle na pas renvoyé un état de sortie déchec si la commande na pas été trouvée. De plus, pour les exécutables, contrairement à which
, elle génère quelque chose comme ls is /bin/ls
au lieu de seulement /bin/ls
ce qui le rendait moins facile à utiliser dans les scripts.
Unix version 8″ s (non publié dans la nature) Bourne shell lavait « s type
intégré renommé en whatis
. Et le shell Plan9 (le successeur unique dUnix) rc
(et son les dérivés comme akanga
et es
) ont également whatis
.
Le shell Korn (un sous-ensemble dont le La définition de POSIX sh
est basée sur), développée au milieu des années 80 mais pas largement disponible avant 1988, a ajouté de nombreuses fonctionnalités csh
( éditeur de lignes, alias …) en haut du shell Bourne. Il a ajouté son propre whence
intégré (en plus de type
) qui a pris plusieurs options (-v
pour fournir la sortie verbeuse semblable à type
, et -p
pour rechercher uniquement les exécutables (pas les alias / fonctions …)) .
Coïncidant avec la tourmente concernant les problèmes de droits dauteur entre AT & T et Berkeley, quelques implémentations de logiciels libres shell sont venues à la fin des années 80 au début des années 90.Lensemble du shell Almquist (ash
, pour remplacer le shell Bourne dans les BSD), limplémentation du domaine public de ksh
(pdksh
), bash
(sponsorisé par la FSF), zsh
est sorti entre 1989 et 1991.
Ash, bien que censé remplacer le shell Bourne, n’avait pas de type
intégré jusqu’à bien plus tard (dans NetBSD 1.3 et FreeBSD 2.3 ), bien quil ait hash -v
. OSF / 1 /bin/sh
avait un type
intégré qui a renvoyé 0 jusquà OSF / 1 v3.x. bash
na « pas ajouté un whence
mais a ajouté un -p
option pour type
pour imprimer le chemin (type -p
serait comme whence -p
) et -a
pour signaler toutes les commandes correspondantes. tcsh
a créé which
intégré et ajouté une commande where
agissant comme bash
» s type -a
. zsh
les a tous.
Le fish
shell (2005) a une commande type
implémentée en tant que fonction.
Le which
Le script csh quant à lui a été supprimé de NetBSD (car il était intégré à tcsh et peu utilisé dans dautres shells), et la fonctionnalité ajoutée à whereis
(lorsquelle est appelée comme which
, whereis
se comporte comme which
sauf quil recherche uniquement les exécutables dans $PATH
). Dans OpenBSD et FreeBSD, which
a également été remplacé par un écrit en C qui recherche les commandes dans $PATH
uniquement .
Implémentations
Il existe des dizaines dimplémentations dun which
co mmand sur divers Unices avec une syntaxe et un comportement différents.
Sous Linux (à côté de ceux intégrés dans tcsh
et zsh
) on trouve plusieurs implémentations. Sur les systèmes Debian récents par exemple, cest « un simple script shell POSIX qui recherche les commandes dans $PATH
.
busybox
a également une commande which
.
Il existe une commande GNU
which
qui est probablement le plus extravagant. Il essaie détendre ce que le script which
csh a fait à dautres shells: vous pouvez lui dire quels sont vos alias et fonctions afin quil puisse donner vous avez une meilleure réponse (et je pense que certaines distributions Linux définissent des alias globaux autour de cela pour que bash
fasse cela).
zsh
a quelques opérateurs à étendre jusquau chemin des exécutables: lopérateur =
extension de nom de fichier et :c
modificateur dexpansion dhistorique (ici appliqué à expansion de paramètres ):
$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls
zsh
, dans le rend également la table de hachage des commandes comme le commands
tableau associatif:
$ print -r -- $commands[ls] /bin/ls
Lutilitaire whatis
(sauf celui du shell Unix V8 Bourne ou Plan 9 rc
/ es
) nest pas vraiment lié car il est uniquement destiné à la documentation (greps la base de données whatis, cest-à-dire le synopsis de la page de manuel « ).
whereis
létait également ajouté dans 3BSD
en même temps que which
bien quil ait été écrit en C
, pas csh
et est utilisé pour rechercher en même temps lexécutable, la page de manuel et la source mais pas en fonction de lenvironnement actuel. Encore une fois, cela répond à un besoin différent.
Maintenant, sur le front standard, POSIX spécifie les command -v
et -V
commandes (qui étaient facultatives jusquà POSIX.2008). UNIX spécifie la commande type
(pas doption). Cest « tout » (where
, which
, whence
ne sont spécifiés dans aucune norme) .
Jusquà certaines versions, type
et command -v
étaient facultatifs dans la spécification Linux Standard Base, ce qui explique pourquoi par exemple, certaines anciennes versions de posh
(bien que basées sur pdksh
qui avaient les deux) nen avaient pas non plus. command -v
a également été ajouté à certaines implémentations Bourne shell (comme sur Solaris).
Statut aujourdhui
Le statut actuel est que type
et command -v
sont omniprésents dans tous les shells de type Bourne (cependant, comme noté par @jarno, notez la mise en garde / bogue dans bash
quand il nest pas en mode POSIX ou certains descendants du shell Almquist ci-dessous dans les commentaires). tcsh
est le seul shell où vous voudriez utiliser which
(car il « ny a pas de type
là et which
est intégré).
Dans les shells autres que tcsh
et zsh
, which
peut vous indiquer le chemin de lexécutable donné tant quil ny a pas dalias ou de fonction du même nom dans lun de nos ~/.cshrc
, ~/.bashrc
ou tout autre fichier de démarrage du shell et vous ne définissez pas $PATH
dans votre ~/.cshrc
. Si vous avez défini un alias ou une fonction pour celui-ci, il peut ou non vous en parler, ou vous dire la mauvaise chose.
Si vous voulez savoir à propos de toutes les commandes par un nom donné, il ny a rien de portable. Vous « utilisez where
dans tcsh
ou zsh
, type -a
dans bash
ou zsh
, whence -a
dans ksh93 et dans dautres shells , vous pouvez utiliser type
en combinaison avec which -a
qui peut fonctionner.
Recommandations
Obtenir le chemin vers un exécutable
Maintenant, pour obtenir le chemin dun exécutable dans un script, il y a quelques mises en garde:
ls=$(command -v ls)
serait la manière standard de le faire.
Il y a cependant quelques problèmes:
- Il nest pas possible de connaître le chemin de lexécutable sans lexécuter. les
type
,which
,command -v
… utilisent tous des heuristiques pour trouver le chemin . Ils parcourent les composants$PATH
et trouvent le premier fichier non-répertoire pour lequel vous avez l’autorisation d’exécution. nding sur le shell, quand il sagit dexécuter la commande, beaucoup dentre eux (Bourne, AT & T ksh, zsh, ash …) les exécuteront simplement dans lordre de$PATH
jusquà ce que lappel systèmeexecve
ne retourne pas avec une erreur. Par exemple, si$PATH
contient/foo:/bar
et que vous souhaitez exécuterls
, ils essaieront dabord pour exécuter/foo/ls
ou si cela échoue/bar/ls
. Maintenant, l’exécution de/foo/ls
peut échouer parce que vous n’avez pas d’autorisation d’exécution, mais aussi pour de nombreuses autres raisons, comme ce n’est pas un exécutable valide.command -v ls
signale/foo/ls
si vous avez lautorisation dexécution pour/foo/ls
, mais exécutantls
peut en fait exécuter/bar/ls
si/foo/ls
nest pas un exécutable valide. - si
foo
est une fonction intégrée ou une fonction ou un alias,command -v foo
renvoiefoo
. Avec certains shells commeash
,pdksh
ouzsh
, il peut également renvoyerfoo
if$PATH
inclut la chaîne vide et il « y a un fichier exécutablefoo
dans le répertoire courant. Dans certaines circonstances, vous devrez peut-être en tenir compte. Gardez à lesprit, par exemple, que la liste des fonctions intégrées varie en fonction de limplémentation du shell (par exemple,mount
est parfois intégrée pour busyboxsh
), et par exemplebash
peuvent obtenir des fonctions de lenvironnement. - if
$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 courant mais peuvent être nimporte quoi), selon le shell,command -v cmd
peut ne pas générer de chemin absolu. Ainsi, le chemin que vous obtenez au moment où vous exécutez ne sera plus valide après que vouscd
ailleurs. - Anecdotique: avec le shell ksh93, si
/opt/ast/bin
(bien que ce chemin exact puisse varier selon les systèmes, je crois) est en vous$PATH
, ksh93 mettra à disposition quelques fonctions intégrées supplémentaires (chmod
,cmp
,cat
…), maiscommand -v chmod
renverra/opt/ast/bin/chmod
même si ce chemin nexiste pas.
Déterminer si une commande existe
Pour savoir si une commande donnée existe en standard, vous pouvez faire:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Où lon pourrait vouloir utiliser which
(t)csh
Dans csh
et tcsh
, vous navez « pas beaucoup de choix. Dans tcsh
, que « Tout va bien car which
est intégré. Dans csh
, ce sera la commande système which
, qui peut ne pas faire ce que vous voulez dans quelques cas.
Rechercher des commandes uniquement dans certains shells
Un cas où il peut être judicieux dutiliser which
est si vous voulez connaître le chemin dune commande, en ignorant le potentiel shell intégré ou fonctions dans bash
, csh
(et non tcsh
), dash
, ou Bourne
scripts shell, cest-à-dire des shells qui nont pas whence -p
(comme ksh
ou zsh
), command -ev
(comme yash
), whatis -p
(rc
, akanga
) ou un (comme tcsh
ou zsh
) sur les systèmes où which
est disponible et nest pas le csh
script.
Si ces conditions sont remplies, alors:
echo=$(which echo)
vous donnerait le chemin du premier echo
dans $PATH
(sauf dans les coins), que echo
soit également un shell builtin / alias / function ou pas.
Dans dautres shells, vous préférez:
- zsh :
echo==echo
ouecho=$commands[echo]
ouecho=${${:-echo}:c}
- ksh , zsh :
echo=$(whence -p echo)
- yash :
echo=$(command -ev echo)
- rc , akanga :
echo=`whatis -p echo`
(attention aux chemins avec des espaces) - poisson :
set echo (type -fp echo)
Notez que si tout ce que vous voulez faire, cest exécuter que echo
commande, vous navez pas à obtenir son chemin, vous pouvez simplement faire:
env echo this is not echoed by the builtin echo
Par exemple, avec tcsh
, pour empêcher lutilisation du which
intégré:
set Echo = "`env which echo`"
Lorsque vous avez besoin dune commande externe
Un autre cas où vous pouvez utiliser which
est celui où vous avez réellement besoin une commande externe. POSIX exige que toutes les commandes internes du shell (comme command
) soient également disponibles en tant que commandes externes, mais malheureusement, ce nest pas le cas pour command
sur de nombreux systèmes. Par exemple, il « est rare de trouver une commande command
sur les systèmes dexploitation Linux alors que la plupart dentre eux ont une which
commande (bien que différentes avec des options et des comportements différents).
Les cas où vous voudrez peut-être quune commande externe soit là où vous exécuteriez une commande sans appeler un shell POSIX.
Le system("some command line")
, popen()
… les fonctions de C ou de divers langages invoquent un shell pour analyser cette ligne de commande, donc system("command -v my-cmd")
y travaillent. Une exception à cela serait perl
qui optimise le shell sil ne voit aucun caractère spécial du shell (autre que lespace). Cela sapplique également à son opérateur de backtick:
$ perl -le "print system "command -v emacs"" -1 $ perl -le "print system ":;command -v emacs"" /usr/bin/emacs 0 $ perl -e "print `command -v emacs`" $ perl -e "print `:;command -v emacs`" /usr/bin/emacs
Lajout de ce :;
ci-dessus force perl
à invoquer un shell là. En utilisant which
, vous n’auriez pas à utiliser cette astuce.
Commentaires
- @Joe,
which
est un scriptcsh
sur de nombreux Unices commerciaux. La raison est historique: ‘ est la raison pour laquelle jai donné lhistorique, afin que les gens comprennent doù il vient, pourquoi les gens se sont habitués à lutiliser et pourquoi il y en a réellement ‘ nest pas une raison pour laquelle vous devriez lutiliser. Et oui, certaines personnes utilisent (t) csh. Tout le monde nutilise pas encore Linux - Après avoir lu cet article, jai trouvé beaucoup de contexte pour la réponse, mais pas la réponse elle-même.Où dans cet article est-il réellement dit pourquoi ne pas utiliser
which
, par opposition aux choses que vous essayez peut-être dutiliserwhich
à faire, lhistorique dewhich
, les implémentations dewhich
, dautres commandes pour effectuer des tâches connexes ou les raisons de lutiliser réellementwhich
? Pourquoi les autres commandes sont meilleures ? Que font-ils différemment dewhich
? Comment éviter ses écueils? Cette réponse passe en fait plus de mots sur les problèmes avec les alternatives que les problèmes avecwhich
. -
command
est décrit par POSIX. - @St é phaneChazelas Si je crée un nouveau fichier par
touch /usr/bin/mytestfile
puis exécutezcommand -v mytestfile
, il donnera le chemin (alors quewhich mytestfile
ne le fait pas). - @jarno, oh oui, vous ‘ à droite.
bash
se réglera sur un fichier non exécutable sil ne peut ‘ trouver un exécutable, donc il ‘ s » OK » (bien quen pratique, on préfèrecommand -v
/type
renvoie une erreur) car ‘ est la commande quil essaierait dexécuter lorsque vous exécutezmytestfile
, mais le comportement dedash
est bogué, comme sil y avait ‘ un non-exécutablecmd
avant un exécutable,command -v
renvoie le non-exécutable lors de lexécutioncmd
exécuterait lexécutable (le mauvais lun est également haché). FreeBSDsh
(également basé surash
) a le même bogue. zsh, yash, ksh, mksh, bash comme sh sont OK.
Answer
Les raisons pour lesquelles on peut ne veulent pas utiliser which
ont déjà été expliqués, mais voici quelques exemples sur quelques systèmes où which
échoue réellement.
Sur les shells de type Bourne, nous « comparons la sortie de which
avec la sortie de type
(type
étant un shell intégré, il est censé être la vérité fondamentale, car cest le shell qui nous dit comment il invoquerait une commande).
De nombreux cas sont coins , mais gardez à lesprit que which
/ type
sont souvent utilisés dans les cas dangle (pour trouver la réponse à un comportement inattendu comme: pourquoi diable cette commande se comporte-t-elle comme ça, laquelle jappelle? ).
La plupart des systèmes, la plupart des shells Bourne: fonctions
Le cas le plus évident concerne les fonctions:
$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls
La raison en est que which
ne rapporte que des exécutables, et parfois des alias (mais pas toujours ceux de votre shell), pas des fonctions.
Le GNU dont la page de manuel a un exemple cassé (car ils ont oublié de citer $@
) sur la façon de lutiliser pour signaler des fonctions également, mais comme pour alias, car il nimplémente pas un analyseur de syntaxe de shell, il est facilement trompé:
$ which() { (alias; declare -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot "$@";} $ f() { echo $"\n}\ng ()\n{ echo bar;\n}\n" >> ~/foo; } $ type f f is a function f () { echo " } g () { echo bar; } " >> ~/foo } $ type g bash: type: g: not found $ which f f () { echo " } $ which g g () { echo bar; }
La plupart des systèmes, la plupart des shells Bourne: builtins
Un autre cas évident est celui des builtins ou des mots-clés, car which
étant une commande externe na aucun moyen de savoir quels buildins ont votre shell (et certains shells comme zsh
, bash
ou ksh
peut charger dynamiquement les fonctions internes):
$ type echo . time echo is a shell builtin . is a shell builtin time is a shell keyword $ which echo . time /bin/echo which: no . in (/bin:/usr/bin) /usr/bin/time
(cela ne sapplique pas à zsh
où which
est intégré)
Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 et bien dautres:
$ csh % which ls ls: aliased to ls -F % unalias ls % which ls ls: aliased to ls -F % ksh $ which ls ls: aliased to ls -F $ type ls ls is a tracked alias for /usr/bin/ls
Cest parce que sur la plupart des Unices commerciaux, which
(comme dans limplémentation dorigine sur 3BSD) est un script csh
qui lit ~/.cshrc
. Les alias quil rapportera sont ceux qui y sont définis quels que soient les alias que vous avez actuellement définis et quel que soit le shell que vous utilisez réellement.
Dans HP / UX ou Tru64:
% echo "setenv PATH /bin:/usr/bin" >> ~/.cshrc % setenv PATH ~/bin:/bin:/usr/bin % ln -s /bin/ls ~/bin/ % which ls /bin/ls
(les versions Solaris et AIX ont résolu ce problème en enregistrant $path
avant de lire le ~/.cshrc
et le restaurer avant de rechercher la (les) commande (s))
$ type "a b" a b is /home/stephane/bin/a b $ which "a b" no a in /usr/sbin /usr/bin no b in /usr/sbin /usr/bin
Ou:
$ d="$HOME/my bin" $ mkdir "$d"; PATH=$PATH:$d $ ln -s /bin/ls "$d/myls" $ type myls myls is /home/stephane/my bin/myls $ which myls no myls in /usr/sbin /usr/bin /home/stephane/my bin
(bien sûr, étant un script csh
, vous ne pouvez pas vous attendre à ce quil fonctionne avec des arguments contenant des espaces …)
CentOS 6.4, bash
$ type which which is aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde" $ alias foo=": "|test|"" $ which foo alias foo=": "|test|"" /usr/bin/test $ alias $"foo=\nalias bar=" $ unalias bar -bash: unalias: bar: not found $ which bar alias bar="
Sur ce système, il existe un alias défini à léchelle du système qui encapsule la commande GNU which
.
La sortie fausse est parce que which
lit la sortie de bash
« s alias
mais ne sait pas comment lanalyser correctement et utilise lheuristique (un alias par ligne, recherche la première commande trouvée après un |
, ;
, &
…)
Le pire sur CentOS est que zsh
a une commande intégrée which
parfaitement correcte mais CentOS a réussi à la casser en la remplaçant par un alias non fonctionnel vers GNU which
.
Debian 7.0, ksh93:
(sapplique à la plupart des systèmes avec de nombreux shells)
$ unset PATH $ which which /usr/local/bin/which $ type which which is a tracked alias for /bin/which
Sur Debian, /bin/which
est un script /bin/sh
. Dans mon cas, sh
étant dash
mais cest pareil quand il « est bash
.
Une PATH
non définie ne consiste pas à désactiver la recherche PATH
, mais à utiliser le système « s PATH par défaut sur lequel malheureusement sur Debian personne nest daccord (dash
et bash
ont /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 dans env
) a :/bin:/usr/bin
(oui, regarde dabord dans le répertoire courant!)) .
Cest pourquoi which
se trompe ci-dessus car il « utilise dash
» par défaut PATH
qui est différent de ksh93
« s
Cest non t mieux avec GNU which
qui rapporte:
which: no which in ((null))
(intéressant, il y a bien un /usr/local/bin/which
sur mon système qui est en fait un script akanga
fourni avec akanga
(un rc
dérivé shell où la valeur par défaut PATH
est /usr/ucb:/usr/bin:/bin:.
))
bash, tout système:
Celui auquel Chris fait référence dans sa réponse :
$ PATH=$HOME/bin:/bin $ ls /dev/null /dev/null $ cp /bin/ls bin $ type ls ls is hashed (/bin/ls) $ command -v ls /bin/ls $ which ls /home/chazelas/bin/ls
Également après avoir appelé hash
manuellement:
$ type -a which which is /usr/local/bin/which which is /usr/bin/which which is /bin/which $ hash -p /bin/which which $ which which /usr/local/bin/which $ type which which is hashed (/bin/which)
Maintenant un cas où which
et parfois type
échouent:
$ mkdir a b $ echo "#!/bin/echo" > a/foo $ echo "#!/" > b/foo $ chmod +x a/foo b/foo $ PATH=b:a:$PATH $ which foo b/foo $ type foo foo is b/foo
Maintenant, avec quelques shells:
$ foo bash: ./b/foo: /: bad interpreter: Permission denied
Avec dautres:
$ foo a/foo
Ni which
ni type
peut savoir à lavance que b/foo
ne peut pas b e exécuté. Certains shells tels que bash
, ksh
ou yash
, lors de lappel de foo
essaiera en effet dexécuter b/foo
et de signaler une erreur, tandis que dautres (comme zsh
, ash
, csh
, Bourne
, tcsh
) sexécutera a/foo
suite à léchec de lappel système execve()
sur b/foo
.
Commentaires
-
mksh
utilise en fait quelque chose de différent pour la valeur par défaut$PATH
: first , la constante de compilation du système dexploitation_PATH_DEFPATH
est utilisée (le plus souvent sur les BSD), puisconfstr(_CS_PATH, …)
est utilisée (POSIX), et si les deux nexistent pas ou échouent,/bin:/usr/bin:/sbin:/usr/sbin
est utilisé. - Dans votre premier exemple, même si
ls
est une fonction quil utilise gls
de PATH. Etwhich
est très bien pour vous dire lequel est utilisé/usr/bin/ls
ou/usr/local/bin/ls
. Je ne ‘ voir » Pourquoi ne pas utiliser lequel » …. - @rudimeier, Que
which ls
me donnera/bin/ls
indépendamment du fait quels
appelle la fonction/bin/ls
ou/opt/gnu/bin/ls
oudir
ou rien du tout. IOW,which
(ce qui implémentations, IMMV) donne quelque chose de non pertinent - @St é phaneChazelas. Non non Non. Je sais déjà que mon
ls
est une fonction. Je sais que ma fonctionls
appellels
depuisPATH
. Maintenant,which
me dit où se trouve le fichier. Vous ne voyez quun seul cas dutilisation: » Que ferait mon shell avec cette commande. » Pour ce cas dutilisationwhich
est faux, correct.Mais il existe dautres cas dutilisation où (GNU)which
est exactement la bonne chose. - @rudimeter, dépend du
which
implémentation. Certains vous diront que ‘ est un alias (si vous avez configuré un alias, ou sil y a un~/.cshrc
dans votre maison qui a tel alias), certains vous donneront un chemin mais le mauvais dans certaines conditions.sh -c 'command -v ls'
, bien que pas parfait, est toujours plus susceptible de vous donner la bonne réponse à cette exigence différente (et est également standard).
Réponse
Une chose qui (daprès mon rapide survol) semble que Stéphane na pas mentionné, cest que which
a aucune idée de la table de hachage du chemin de votre shell. Cela a pour effet de renvoyer un résultat qui nest pas représentatif de ce qui est réellement exécuté, ce qui le rend inefficace pour le débogage.
Réponse
Jai lhabitude de grincer des dents lorsque cette question est recommandée aux utilisateurs sans méfiance, car dénigrer sans fondement which
nest utile à personne.
Si which
fonctionne bien et fournit la réponse correcte à certaines tâches, en suivant le mot dordre Unix: faites une chose, faites-la bien , pourquoi which
être banni?
La question devrait être, alors, laquelle fonctionne bien et fait bien un travail spécifique?
Dune part, lutilitaire externe de / bin / qui dans Debian est un script shell dont le but est uniquement de lister les exécutables du nom donné sur le chemin. Je crois que which
réalise correctement son objectif. Il ne charge aucun alias, aucune fonction, rien du shell, liste juste les premiers (ou tous) exécutables du nom donné sur le PATH. Le signifiant davoir trouvé un fichier avec le même nom que celui donné est quelque chose que lutilisateur devrait comprendre par elle (lui) self.
Oui, dautres implémentations de which
peuvent (et ont généralement) des problèmes particuliers.
Réponse
On entend souvent ce quil faut éviter. Pourquoi? Que devrions-nous utiliser à la place?
Je nai jamais entendu cela. Veuillez fournir des exemples spécifiques. Je minquiéterais de votre distribution Linux et des packages logiciels installés, car cest doù vient which
!
SLES 11.4 x86-64
dans tcsh version 6.18.01:
> which which which: shell built-in command.
dans la version bash 3.2-147:
> which which /usr/bin/which > which -v GNU which v2.19, Copyright (C) 1999 - 2008 Carlo Wood. GNU which comes with ABSOLUTELY NO WARRANTY; This program is free software; your freedom to use, change and distribute this program is protected by the GPL.
which
fait partie de util-linux un paquet standard distribué par lorganisation du noyau Linux pour une utilisation dans le cadre du système dexploitation Linux. Il fournit également ces autres fichiers
/bin/dmesg /bin/findmnt /bin/logger /bin/lsblk /bin/more /bin/mount /bin/umount /sbin/adjtimex /sbin/agetty /sbin/blkid /sbin/blockdev /sbin/cfdisk /sbin/chcpu /sbin/ctrlaltdel /sbin/elvtune /sbin/fdisk /sbin/findfs /sbin/fsck /sbin/fsck.cramfs /sbin/fsck.minix /sbin/fsfreeze /sbin/fstrim /sbin/hwclock /sbin/losetup /sbin/mkfs /sbin/mkfs.bfs /sbin/mkfs.cramfs /sbin/mkfs.minix /sbin/mkswap /sbin/nologin /sbin/pivot_root /sbin/raw /sbin/sfdisk /sbin/swaplabel /sbin/swapoff /sbin/swapon /sbin/switch_root /sbin/wipefs /usr/bin/cal /usr/bin/chrp-addnote /usr/bin/chrt /usr/bin/col /usr/bin/colcrt /usr/bin/colrm /usr/bin/column /usr/bin/cytune /usr/bin/ddate /usr/bin/fallocate /usr/bin/flock /usr/bin/getopt /usr/bin/hexdump /usr/bin/i386 /usr/bin/ionice /usr/bin/ipcmk /usr/bin/ipcrm /usr/bin/ipcs /usr/bin/isosize /usr/bin/line /usr/bin/linux32 /usr/bin/linux64 /usr/bin/look /usr/bin/lscpu /usr/bin/mcookie /usr/bin/mesg /usr/bin/mkzimage_cmdline /usr/bin/namei /usr/bin/rename /usr/bin/renice /usr/bin/rev /usr/bin/script /usr/bin/scriptreplay /usr/bin/setarch /usr/bin/setsid /usr/bin/setterm /usr/bin/tailf /usr/bin/taskset /usr/bin/time /usr/bin/ul /usr/bin/uname26 /usr/bin/unshare /usr/bin/uuidgen /usr/bin/wall /usr/bin/whereis /usr/bin/which /usr/bin/write /usr/bin/x86_64 /usr/sbin/addpart /usr/sbin/delpart /usr/sbin/fdformat /usr/sbin/flushb /usr/sbin/freeramdisk /usr/sbin/klogconsole /usr/sbin/ldattach /usr/sbin/partx /usr/sbin/rcraw /usr/sbin/readprofile /usr/sbin/rtcwake /usr/sbin/setctsid /usr/sbin/tunelp
my util-linux
est la version 2.19. Les notes de mise à jour peuvent être facilement retrouvées à la v2.13 datée du (28 août 2007). Je ne sais pas quel était le but ou lobjectif de ceci, il na certainement pas été répondu à cette longue chose 331 fois votée pour.
Commentaires
- Remarquez comment le question ne fait aucune mention de ce à quoi Unix il se réfère. Linux nest quun exemple parmi dautres.
- Comme le montre votre
which -v
, ce GNU ‘ qui (lextravagant lun mentionné dans lautre réponse et nest en aucun cas spécifique à Linux), pas util-linux qui AFAIK na jamais inclus dutilitairewhich
. util-linux 2.19 est de 2011, GNU qui 2.19 est de 2008.
which
supposent un contexte de shell interactif. la question dans ce contexte comme » quoi utiliser à la place dewhich
pour trouver le premier exécutable dun nom donné dans le$PATH
« . La plupart des réponses et des raisons contrewhich
traitent des alias, des fonctions intégrées et des fonctions qui, dans la plupart des scripts shell portables du monde réel, ne présentent quun intérêt académique. Les alias définis localement ne sont pas ‘ hérités lors de lexécution dun script shell (sauf si vous le sourcez avec.
).csh
(etwhich
est toujours un scriptcsh
sur la plupart des publicités Unices) lit~/.cshrc
lorsquil nest pas interactif. Cest ‘ pourquoi vous ‘ remarquerez que les scripts csh commencent généralement par#! /bin/csh -f
.which
ne le fait pas car il vise à vous donner les alias, car il ‘ est conçu comme un outil pour (interactif) utilisateurs decsh
. Les utilisateurs de shells POSIX ontcommand -v
.(t)csh
(ou si vous ‘ cela ne vous dérange pas si ‘ t vous donne le résultat correct), utiliseztype
oucommand -v
à la place . Voir les réponses pour pourquoi .stat $(which ls)
est faux pour plusieurs raisons (, guillemets manquants), pas seulement lutilisation dewhich
). Vous ‘ utilisezstat -- "$(command -v ls)"
. Cela suppose quels
est bien une commande trouvée sur le système de fichiers (pas une fonction interne de votre shell, ou une fonction dalias).which
peut vous donner le mauvais chemin (pas le chemin que votre shell exécuterait si vous entrezls
) ou vous donne un alias tel que défini dans la configuration de certains autres shells …which
ne vous donneraient même pas lels
qui serait trouvé par une recherche de$PATH
(indépendamment de ce quels
peut invoquer 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
est un héritage brisé decsh
.