`qui`, mais tous

19

Je pense que la plupart connaissent la whichcommande et je l'utilise fréquemment. Je suis juste tombé sur une situation où je suis curieux non seulement de savoir quelle commande est la première sur mon chemin, mais combien et où se trouvent toutes les commandes dans tous mes chemins. J'ai essayé la page de manuel which (la frappe man whichm'a fait rire), mais je n'ai rien vu.

kenny
la source
1
Sur mon système, il est la première chose inscrite à la page de manuel: which --all.
Shawn J.Goff
2
Sur le mien (linux) c'est seulement which -a.
utilisateur inconnu

Réponses:

23

Sur certains systèmes, which -aaffiche toutes les correspondances. Si votre shell est bash ou zsh¹, vous pouvez utiliser à la typeplace: type fooaffiche la première correspondance et type -a fooaffiche toutes les correspondances. Les trois commandes type, whichet whencefont principalement la même chose; ils diffèrent entre les shells et les systèmes d'exploitation en termes de disponibilité, d'options et de ce qu'ils rapportent exactement. typeest toujours disponible et affiche tous les noms possibles de type commande (alias, mots clés, fonctions intégrées du shell, fonctions et commandes externes).

La seule façon entièrement portable d'afficher toutes les correspondances est de $PATHvous analyser . Voici un script shell qui fait cela. Si vous en faites une fonction shell, assurez-vous de placer le corps de la fonction entre parenthèses (afin que la modification passe à la fonction IFSet set -fn'échappe pas à celle-ci), puis changez exiten return.

#!/bin/sh
set -f       # disable globbing
IFS=:        # break words at : only
not_found=1
for d in $PATH; do
  if [ -f "$d/$x" ] && [ -x "$d/$x" ]; then
    printf '%s\n' "$d/$x"
    not_found=0
  fi
done
exit $not_found

¹ Ou ksh 93, selon la documentation, bien que ksh 93s + 2008-01-31 n'imprime que la première correspondance lorsque j'essaye.

Gilles 'SO- arrête d'être méchant'
la source
Ce shcode ne fonctionne pas correctement s'il y a des composants vides dans $PATH. Notez également qu'il $IFSs'agit d'un délimiteur de champ (dans les shells POSIX au moins) tandis que dans $PATH, le signe deux-points est utilisé comme séparateur de champ . Voir le whichscript trouvé sur Debian pour une implémentation correcte.
Stéphane Chazelas
la fonction typeintégrée ksh93u+ 2012-08-01semble fonctionner correctement.
Stéphane Chazelas
5

Le drapeau --all ou -a vous montrera toutes les correspondances sur votre chemin et les alias (au moins sur Fedora, Ubuntu et CentOS):

which -a which

Sous AIX et Solaris, cela vous rapprochera:

echo "$PATH" | sed -e 's/:/ /g' | \
while read -r p; do find "$p" -type f -name "which"; done
Eli Heady
la source
Vous avez besoin de guillemets doubles autour des substitutions de paramètres, sinon le script ne fonctionnera pas s'il $PATHcontient des espaces ou des caractères globbing shell. read -rest nécessaire pour faire face aux barres obliques inverses. Ce n'est pas une bonne méthode car findcela prendra du temps et peut retourner des correspondances parasites si un répertoire dans $PATHcontient des sous-répertoires. Heureusement, findn'est pas utile ici; voir ma réponse.
Gilles 'SO- arrête d'être méchant'
Je savais que trouver se sentait mal car il serait certainement lent dans les répertoires imbriqués. Globbing et espaces dans $ PATH? eww. Mais vous avez raison (bien que vous ayez été assez gentil pour ne pas en dire autant): ma seule doublure était mal écrite.
Eli Heady
1

Si vous n'avez pas de whichsupport -aou whencedisponible, lancez le vôtre:

#!/bin/sh -f

IFS=":"
for PART in $PATH
do
  if test -x "$PART/$1"
  then
    echo $PART/$1
  fi
done
MattBianco
la source
Vous manquez set -fpour désactiver le globbing sur le non protégé $PATH. test -fn'est pas suffisant car seuls les fichiers exécutables sont recherchés ici; vous avez besoin test -x. Hmm, je réalise que j'ai oublié le test de fichier normal dans mon script.
Gilles 'SO- arrête d'être méchant'
@Gilles: édité selon vos conseils. Je suis tout à fait correct, mais je trouve whence README.txtaussi peu probable que whence "file* wi?h we!rd name". J'essaie juste de montrer à quel point il est facile de traverser $PATH.
MattBianco
0

ksh et zsh ont "d'où" un shell intégré. whence -afait ce que vous voulez sous zsh:

 7:27AM 7 % whence -a cat
/usr/bin/cat
/bin/cat
/usr/bin/cat
/bin/cat

Je dois nettoyer PATH dans zsh, j'ai beaucoup de doublons dedans. whence -afonctionne différemment sous ksh:

$ whence -a cat
cat is a tracked alias for /usr/bin/cat

Je dois dire que cela semble également être un comportement potentiellement utile.

Bruce Ediger
la source