Pourquoi ne pas utiliser “ qui ”? Que utiliser alors?

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

  • Je pense que la plupart des arguments contre l’utilisation de which supposent un contexte de shell interactif. la question dans ce contexte comme  » quoi utiliser à la place de which pour trouver le premier exécutable dun nom donné dans le $PATH « . La plupart des réponses et des raisons contre which 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 .).
  • @MattBianco, oui, csh (et which est toujours un script csh 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 de csh. Les utilisateurs de shells POSIX ont command -v.
  • @rudimeier, alors la réponse serait toujours sauf si votre shell est (t)csh (ou si vous ‘ cela ne vous dérange pas si ‘ t vous donne le résultat correct), utilisez type ou command -v à la place . Voir les réponses pour pourquoi .
  • @rudimeier, (stat $(which ls) est faux pour plusieurs raisons (, guillemets manquants), pas seulement lutilisation de which). Vous ‘ utilisez stat -- "$(command -v ls)". Cela suppose que ls 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 entrez ls) ou vous donne un alias tel que défini dans la configuration de certains autres shells …
  • @rudimeier, encore une fois, il y a un certain nombre de conditions dans lesquelles de nombreuses implémentations which ne vous donneraient même pas le ls qui serait trouvé par une recherche de $PATH (indépendamment de ce que ls peut invoquer dans votre shell). sh -c 'command -v ls' ou zsh -c 'rpm -q --whatprovides =ls' sont plus susceptibles de vous donner la bonne réponse. Le point ici est que which est un héritage brisé de csh.

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ème execve ne retourne pas avec une erreur. Par exemple, si $PATH contient /foo:/bar et que vous souhaitez exécuter ls, 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écutant ls 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 renvoie foo. Avec certains shells comme ash, pdksh ou zsh, il peut également renvoyer foo if $PATH inclut la chaîne vide et il « y a un fichier exécutable foo 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 busybox sh), et par exemple bash 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 vous cd 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 …), mais command -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 ou echo=$commands[echo] ou echo=${${:-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 script csh 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 dutiliser which à faire, lhistorique de which, les implémentations de which, dautres commandes pour effectuer des tâches connexes ou les raisons de lutiliser réellement which? Pourquoi les autres commandes sont meilleures ? Que font-ils différemment de which? Comment éviter ses écueils? Cette réponse passe en fait plus de mots sur les problèmes avec les alternatives que les problèmes avec which.
  • command est décrit par POSIX.
  • @St é phaneChazelas Si je crée un nouveau fichier par touch /usr/bin/mytestfile puis exécutez command -v mytestfile, il donnera le chemin (alors que which 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ère command -v / type renvoie une erreur) car ‘ est la commande quil essaierait dexécuter lorsque vous exécutez mytestfile, mais le comportement de dash est bogué, comme sil y avait ‘ un non-exécutable cmd avant un exécutable, command -v renvoie le non-exécutable lors de lexécution cmd exécuterait lexécutable (le mauvais lun est également haché). FreeBSD sh (également basé sur ash) 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 à zshwhich 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), puis confstr(_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 g ls de PATH. Et which 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 que ls appelle la fonction /bin/ls ou /opt/gnu/bin/ls ou dir 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 fonction ls appelle ls depuis PATH. 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 dutilisation which 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 dutilitaire which. util-linux 2.19 est de 2011, GNU qui 2.19 est de 2008.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *