Pregunta ¿Cómo verificar si existe un programa desde un script Bash?


¿Cómo podría validar que existe un programa, de forma que devuelva un error y salga, o continúe con el script?

Parece que debería ser fácil, pero me ha estado golpeando.


1573
2018-02-26 21:52


origen


Respuestas:


Responder

Compatible con POSIX:

command -v <the_command>

por bash entornos específicos:

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

Explicación

Evitar which. No solo se trata de un proceso externo que está iniciando para hacer muy poco (es decir, construcciones internas como hash, type o command son mucho más baratas), también puede confiar en que las instrucciones internas realmente harán lo que desee, mientras que los efectos de los comandos externos pueden variar fácilmente de un sistema a otro.

¿Por qué importa?

  • Muchos sistemas operativos tienen una which ese ni siquiera establece un estado de salida, significando el if which foo ni siquiera va a funcionar allí y lo hará siempre reporta eso foo existe, incluso si no lo hace (tenga en cuenta que algunos shells POSIX parecen hacer esto para hash también).
  • Muchos sistemas operativos hacen which hacer cosas personalizadas y malvadas como cambiar la salida o incluso enganchar en el administrador de paquetes.

Entonces, no uses which. En su lugar, use uno de estos:

$ 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; }

(Nota secundaria: algunos sugerirán 2>&- es el mismo 2>/dev/null pero más corto esto no es cierto. 2>&- cierra FD 2 que causa un error en el programa cuando intenta escribir en stderr, que es muy diferente de escribir con éxito y descartar la salida (¡y peligroso!)

Si tu hash bang es /bin/sh entonces deberías preocuparte por lo que dice POSIX. type y hashlos códigos de salida de POSIX no están bien definidos por POSIX, y hash se ve que sale exitosamente cuando el comando no existe (no lo he visto con type todavía). commandEl estado de salida de POSIX está bien definido por POSIX, por lo que uno es probablemente el más seguro de usar.

Si tu script usa bash sin embargo, las reglas POSIX realmente ya no importan y ambos type y hash ser perfectamente seguro de usar type ahora tiene una -P para buscar solo el PATH y hash tiene el efecto secundario de que la ubicación del comando será hash (para una búsqueda más rápida la próxima vez que lo uses), lo que generalmente es bueno ya que probablemente verifiques su existencia para poder usarla realmente.

Como un simple ejemplo, aquí hay una función que se ejecuta gdate si existe, de lo contrario date:

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

2277
2018-03-24 12:45



La siguiente es una forma portátil de verificar si existe un comando en $PATH  y es ejecutable:

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

Ejemplo:

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

La comprobación ejecutable es necesaria porque bash devuelve un archivo no ejecutable si no se encuentra ningún archivo ejecutable con ese nombre en $PATH.

También tenga en cuenta que si existe un archivo no ejecutable con el mismo nombre que el ejecutable anteriormente en $PATH, dash devuelve el primero, a pesar de que el último sería ejecutado. Este es un error y está en violación del estándar POSIX. [Informe de error] [Estándar]

Además, esto fallará si el comando que está buscando se ha definido como un alias.


236
2017-11-05 14:33



Estoy de acuerdo con lhunath para desalentar el uso de which, y su solución es perfectamente válida para usuarios de BASH. Sin embargo, para ser más portátil, command -v se usará en su lugar:

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

Mando command cumple con POSIX, mira aquí para su especificación: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html

Nota: type es compatible con POSIX, pero type -P no es.


190
2018-01-24 18:16



Tengo una función definida en mi .bashrc que hace esto más fácil.

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

Aquí hay un ejemplo de cómo se usa (de mi .bash_profile.)

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

81
2017-10-14 09:24



Depende de si desea saber si existe en uno de los directorios en el $PATH variable o si conoce la ubicación absoluta de la misma. Si quieres saber si está en el $PATH variable, uso

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

de otro modo usar

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

La redirección a /dev/null/ en el primer ejemplo suprime la salida de la which programa.


66
2018-02-26 22:01



Expandiendo las respuestas de @lhunath y @ GregV, aquí está el código para las personas que quieren poner fácilmente ese cheque dentro de una if declaración:

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

He aquí cómo usarlo:

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

27
2017-12-07 21:17



Intenta usar:

test -x filename

o

[ -x filename ]

Desde la página de manual de bash debajo Expresiones condicionales:

 -x file
          True if file exists and is executable.

19
2018-02-26 21:57