Comment puis-je tester pour voir si une application existe dans $ PATH?

19

J'essaie d'écrire tous mes shscripts startup / env pour travailler avec autant de DRY et autant: "fonctionne sur chaque * nix sur lequel je le clone", autant que possible. Cela signifie m'assurer que si j'essaie d'exécuter du code qui n'est pas là, que le code échoue gracieusement. À cette fin, je dois pouvoir tester si des programmes existent. Je sais comment tester si un fichier existe, mais je ne sais pas comment tester pour voir si une application est exécutable dans le chemin. Je préfère utiliser $ PATH, car certains d'entre eux doivent fonctionner sur arch, ubuntu et centos. Certains peuvent être installés dans mon homedir, sur des systèmes où je n'ai pas de racine, d'autres peuvent ne pas être installés, et d'autres encore peuvent être installés dans des chemins d'accès système.

xénoterracide
la source
2
Cette réponse SO est celle que j'ai mise en signet pour de telles questions.
jw013

Réponses:

19

Utilisez type commandname. Cela retourne vrai si commandnamequelque chose est exécutable: alias, fonction, commande intégrée ou externe (recherchée dans $PATH). Vous pouvez également utilisercommand commandname qui renvoie true si commandnameest une commande intégrée ou externe (recherchée dans $PATH).

exists () {
  type "$1" >/dev/null 2>/dev/null
}

Il y a quelques variantes sh (certainement pré-POSIX; je connais /bin/shsous OSF1 ≤3.x et certaines versions du shell Almquist trouvées dans les premières versions de NetBSD et quelques distributions Linux du 20e siècle) oùtype renvoie toujours 0 ou non exister. Je ne pense pas que des systèmes soient livrés avec ceux-ci ce millénaire. Si vous les rencontrez, voici une fonction que vous pouvez utiliser pour rechercher $PATHmanuellement:

exists () { (
    IFS=:
    for d in $PATH; do
      if test -x "$d/$1"; then return 0; fi
    done
    return 1
) }

Cette fonction est généralement utile si vous souhaitez exclure les fonctions intégrées et rechercher le nom dans $PATH. La plupart des shells ont une fonction intégrée pour cela, command -vbien qu'il s'agisse d'un ajout relativement récent à POSIX (toujours facultatif à partir de POSIX: 2004). Il s'agit essentiellement d'une version conviviale de type: il affiche le chemin complet d'un exécutable dans $PATH, le nom nu pour une fonction intégrée ou, et une définition d'alias pour un alias.

exists_in_path () {
  case $(command -v -- "$1") in
    /*) return 0;;
    alias\ *) return 1;; # alias
    *) return 1;; # built-in or function
  esac
}

Ksh, bash et zsh doivent également type -prechercher uniquement les exécutables dans $PATH. Notez qu'en bash, le statut de retour type -p fooest 0 s'il foos'agit d'une fonction intégrée ou; si vous souhaitez tester un exécutable dans $PATH, vous devez vérifier que la sortie n'est pas vide. type -pn'est pas dans POSIX; par exemple, la cendre de Debian (qui est /bin/shsur Ubuntu) ne l'a pas.

Gilles 'SO- arrête d'être méchant'
la source
@ Gilles, cela (ou quelque chose de similaire) if [ type keychain ]; thenne fonctionnera-t-il pas? Je reçois une erreur, /home/xenoterracide/.zshrc:84: parse error: condition expected: typeje suppose que je pourrais écrire la fonction existe ... Je pensais juste que cela pourrait être plus simple dans un sens ...
xenoterracide
@xenoterracide: laissez tomber les crochets!
Gilles 'SO- arrête d'être méchant'
Je pense que vous cherchez if type $APP >/dev/null 2>/dev/null; then ...Vous ne voulez pas le [].
Steven D
4
Bah, je savais que j'aurais dû me rafraîchir. Battu à nouveau par Gilles!
Steven D
type -psi vous recherchez spécifiquement une commande $PATH(pas d'alias, de fonctions ou de commandes intégrées).
éphémère
1

Si vous recherchez uniquement des programmes externes, vous pouvez également les utiliser. Je ne sais pas à quel point c'est portable.

Kim
la source
3
En théorie, c'est moins portable que typeou command; whichn'est pas dans POSIX, par exemple. En pratique, whichil existe presque partout, mais à certains endroits (où il est implémenté en tant que script csh), il utilise un chemin différent (en raison de a .cshrc), ce qui va à l'encontre du but.
Gilles 'SO- arrête d'être méchant'