¿Cómo puedo comprobar si existe un programa desde un script Bash?
¿Cómo validaría que existe un programa, de manera que devuelva un error y salga, o continúe con el script?
Parece que debería ser fácil, pero me ha dejado perplejo.
Respuesta
Compatible con POSIX:
command -v <the_command>
Uso de ejemplo:
if ! command -v <the_command> &> /dev/null
then
echo "<the_command> could not be found"
exit 1
fi
Para entornos específicos de Bash:
hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords
Explicación
Evitar which
. No solo es un proceso externo que estás iniciando para hacer muy poco (lo que significa que las funciones integradas como hash
, type
o command
son mucho más baratas), también puedes confiar en las funciones integradas para hacer lo que quieres, mientras que los efectos de los comandos externos pueden variar fácilmente de sistema a sistema.
¿Por qué preocuparse?
- Muchos sistemas operativos tienen un
which
que ni siquiera establece un estado de salida , lo que significa queif which foo
ni siquiera funcionará allí y siempre informará quefoo
existe, incluso si no es así (tenga en cuenta que algunos shells POSIX parecen hacer estohash
también). - Muchos sistemas operativos hacen
which
cosas personalizadas y malvadas, como cambiar la salida o incluso conectarse al administrador de paquetes.
Así que no uses which
. En su lugar, utilice 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 al margen menor: algunos sugerirán 2>&-
que es lo mismo 2>/dev/null
pero más corto; esto no es cierto . 2>&-
Cierra FD 2, lo que provoca un error en el programa cuando intenta escribir en stderr, lo cual es muy diferente a escribirlo 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 hash
los códigos de salida de POSIX no están muy bien definidos y hash
se ve que salen exitosamente cuando el comando no existe (aún no he visto esto type
). command
El estado de salida de está bien definido por POSIX, por lo que probablemente sea el más seguro de usar.
Sin embargo, si su script lo usa bash
, las reglas POSIX ya no importan y ambas type
se hash
vuelven perfectamente seguras de usar. type
ahora tiene un -P
para buscar solo PATH
y hash
tiene el efecto secundario de que la ubicación del comando será codificada (para una búsqueda más rápida la próxima vez que lo use), lo cual generalmente es algo bueno ya que probablemente verifique su existencia para poder usarlo realmente. .
Como ejemplo simple, 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
}
Alternativa con un conjunto completo de funciones
Puede utilizar scripts comunes para satisfacer sus necesidades.
Para comprobar si hay algo instalado, puedes hacer:
checkBin <the_command> || errorMessage "This tool requires <the_command>. Install it please, and then run this tool again."
La siguiente es una forma portátil de comprobar si un comando existe $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 verificación del 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
, el guión devuelve el primero, aunque el segundo se ejecutaría. Esto es un error y viola el estándar POSIX. [ Informe de error ] [ Estándar ]
Editar : Esto parece estar solucionado a partir de Dash 0.5.11 (Debian 11).
Además, esto fallará si el comando que busca se ha definido como alias.
Estoy de acuerdo con lhunath en desalentar el uso de which
, y su solución es perfectamente válida para los usuarios de Bash . Sin embargo, para que sea más portátil, command -v
se utilizará en su lugar:
$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed. Aborting." >&2; exit 1; }
El comando command
es compatible con POSIX. Consulte aquí para conocer su especificación: comando: ejecute un comando simple
Nota: type
es compatible con POSIX, pero type -P
no lo es.
Depende de si desea saber si existe en uno de los directorios de la $PATH
variable o si conoce su ubicación absoluta. Si quieres saber si está en la $PATH
variable, usa
if which programname >/dev/null; then
echo exists
else
echo does not exist
fi
de lo contrario 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 del which
programa.