Question Comment vérifier si un programme existe à partir d'un script Bash?


Comment est-ce que je validerais qu'un programme existe, d'une manière qui retournera une erreur et quittera, ou continuera avec le manuscrit?

Il semble que ça devrait être facile, mais ça m'a bousculé.


1573
2018-02-26 21:52


origine


Réponses:


Répondre

POSIX compatible:

command -v <the_command>

Pour bash environnements spécifiques:

hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords

Explication

Éviter which. Non seulement c'est un processus externe que vous lancez pour faire très peu de choses (ce qui veut dire des builtins comme hash, type ou command sont beaucoup moins chers), vous pouvez également compter sur les builtins pour faire ce que vous voulez, tandis que les effets des commandes externes peuvent facilement varier d'un système à l'autre.

Pourquoi s'en soucier?

  • De nombreux systèmes d'exploitation ont un which cette ne définit même pas un statut de sortie, ce qui signifie le if which foo ne va même pas travailler là-bas et toujours signale cela foo existe, même si ce n'est pas le cas (notez que certains obus POSIX semblent faire cela pour hash aussi).
  • De nombreux systèmes d'exploitation font which faire des choses personnalisées et mauvaises comme changer la sortie ou même accrocher dans le gestionnaire de paquets.

Donc, n'utilisez pas which. Au lieu de cela, utilisez l'un d'entre eux:

$ command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
$ type foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }
$ hash foo 2>/dev/null || { echo >&2 "I require foo but it's not installed.  Aborting."; exit 1; }

(Note secondaire: certains suggéreront 2>&- est le même 2>/dev/null mais plus court - c'est faux. 2>&- ferme FD 2 qui provoque une Erreur dans le programme quand il essaie d'écrire sur stderr, ce qui est très différent d'écrire avec succès et d'abandonner la sortie (et dangereux!))

Si votre hash bang est /bin/sh alors vous devriez vous préoccuper de ce que dit POSIX. type et hashLes codes de sortie ne sont pas très bien définis par POSIX, et hash est vu pour quitter avec succès quand la commande n'existe pas (n'ont pas vu cela avec type encore). commandLe statut de sortie est bien défini par POSIX, de sorte que l'un est probablement le plus sûr à utiliser.

Si votre script utilise bash Cependant, les règles POSIX ne comptent plus vraiment et les deux type et hash devenir parfaitement sûr à utiliser. type a maintenant un -P pour rechercher seulement le PATH et hash a l'effet de bord que l'emplacement de la commande sera haché (pour une recherche plus rapide la prochaine fois que vous l'utiliserez), ce qui est généralement une bonne chose puisque vous vérifiez probablement son existence pour l'utiliser réellement.

Comme un exemple simple, voici une fonction qui fonctionne gdate s'il existe, sinon date:

gnudate() {
    if hash gdate 2>/dev/null; then
        gdate "$@"
    else
        date "$@"
    fi
}

2277
2018-03-24 12:45



Ce qui suit est un moyen portable de vérifier si une commande existe dans $PATH  et est exécutable:

[ -x "$(command -v foo)" ]

Exemple:

if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  exit 1
fi

La vérification de l'exécutable est nécessaire car bash retourne un fichier non exécutable si aucun fichier exécutable portant ce nom n'est trouvé dans $PATH.

Notez également que si un fichier non exécutable portant le même nom que l'exécutable existe plus tôt dans $PATH, dash renvoie le premier, même si le dernier serait exécuté. Ceci est un bug et est en violation de la norme POSIX. [Rapport d'erreur] [la norme]

En outre, cela échouera si la commande que vous recherchez a été définie en tant qu'alias.


236
2017-11-05 14:33



Je suis d'accord avec lhunath pour décourager l'utilisation de whichet sa solution est parfaitement valide pour les utilisateurs de BASH. Cependant, pour être plus portable, command -v doit être utilisé à la place:

$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed.  Aborting." >&2; exit 1; }

Commander command est conforme POSIX, voir ici pour sa spécification: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html

Remarque: type POSIX est conforme, mais type -P n'est pas.


190
2018-01-24 18:16



J'ai une fonction définie dans mon .bashrc qui rend cela plus facile.

command_exists () {
    type "$1" &> /dev/null ;
}

Voici un exemple de la façon dont il est utilisé (de mon .bash_profile.)

if command_exists mvim ; then
    export VISUAL="mvim --nofork"
fi

81
2017-10-14 09:24



Cela dépend si vous voulez savoir s'il existe dans l'un des répertoires du $PATH variable ou si vous connaissez l'emplacement absolu de celui-ci. Si vous voulez savoir si c'est dans le $PATH variable, utilisation

if which programname >/dev/null; then
    echo exists
else
    echo does not exist
fi

sinon utiliser

if [ -x /path/to/programname ]; then
    echo exists
else
    echo does not exist
fi

La redirection vers /dev/null/ dans le premier exemple supprime la sortie de la which programme.


66
2018-02-26 22:01



S'étendant sur les réponses de @ lhunath et de @ GregV, voici le code pour les personnes qui veulent mettre facilement cette vérification dans un if déclaration:

exists()
{
  command -v "$1" >/dev/null 2>&1
}

Voici comment l'utiliser:

if exists bash; then
  echo 'Bash exists!'
else
  echo 'Your system does not have Bash'
fi

27
2017-12-07 21:17



Essayez d'utiliser:

test -x filename

ou

[ -x filename ]

De la page de manuel bash sous Expressions conditionnelles:

 -x file
          True if file exists and is executable.

19
2018-02-26 21:57



Utiliser hash, comme @lhunath suggère, dans un script bash:

hash foo &> /dev/null
if [ $? -eq 1 ]; then
    echo >&2 "foo not found."
fi

Ce script s'exécute hash puis vérifie si le code de sortie de la commande la plus récente, la valeur stockée dans $?, est égal à 1. Si hash ne trouve pas foo, le code de sortie sera 1. Si foo est présent, le code de sortie sera 0.

&> /dev/null redirige l'erreur standard et la sortie standard de hash de sorte qu'il n'apparaisse pas à l'écran et echo >&2 écrit le message à l'erreur standard.


16
2018-06-24 17:01



Je n'ai jamais eu les solutions ci-dessus pour travailler sur la boîte à laquelle j'ai accès. Pour un, le type a été installé (faire ce que fait plus). Donc, la directive intégrée est nécessaire. Cette commande fonctionne pour moi:

if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi

7
2017-07-11 18:38



Si vous vérifiez l'existence du programme, vous allez probablement l'exécuter plus tard de toute façon. Pourquoi ne pas essayer de l'exécuter en premier lieu?

if foo --version >/dev/null 2>&1; then
    echo Found
else
    echo Not found
fi

C'est une vérification plus fiable que le programme s'exécute que de simplement regarder les répertoires PATH et les autorisations de fichiers.

De plus, vous pouvez obtenir un résultat utile de votre programme, comme sa version.

Bien sûr, les inconvénients sont que certains programmes peuvent être lourds à démarrer et d'autres n'ont pas --version option pour quitter immédiatement (et avec succès).


7
2017-07-08 15:14