¿Qué es un "programa"? ¿Incluye funciones y alias? whichdevuelve cierto para estos. typesin argumentos, también devolverá verdadero para las palabras reservadas y los componentes integrados de shell. Si "programa" significa "ejecutable en $PATH", vea esta respuesta .
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á iniciando por hacer muy poco (lo que significa que las funciones integradas hash, typeocommand son mucho más barato), también puede depender de las órdenes internas para hacer realidad lo que quiere, mientras que los efectos de los comandos externos pueden variar fácilmente de sistema a sistema.
¿Por qué importa?
Muchos sistemas operativos tienen un sistema whichque ni siquiera establece un estado de salida , lo que significa if which fooque ni siquiera funcionará allí y siempre informará que fooexiste, incluso si no existe (tenga en cuenta que algunos shells POSIX parecen hacer esto parahash ).
Muchos sistemas operativos hacen whichcosas personalizadas y malvadas como cambiar la salida o incluso conectarse al administrador de paquetes.
Entonces, no lo 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 al margen menor: algunos sugerirán que 2>&-es igual 2>/dev/nullpero 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 su hash bang es, /bin/shentonces debería preocuparse por lo que dice POSIX. typey hashlos códigos de salida de POSIX no están terriblemente bien definidos, y hashse ve que sale con éxito cuando el comando no existe (todavía no lo he visto type). commandPOSIX define bien el estado de salida, por lo que probablemente sea el más seguro de usar.
Si sus usos de guión bashsin embargo, las normas POSIX realmente no importa más y tanto typey hashse vuelven perfectamente seguro para su uso. typeahora tiene -Pque buscar solo el PATHyhash tiene el efecto secundario de que la ubicación del comando se cambiará (para una búsqueda más rápida la próxima vez que lo use), lo que generalmente es algo bueno, ya que probablemente verifique su existencia para usarlo realmente .
Como ejemplo simple, aquí hay una función que se ejecuta gdatesi existe, de lo contrario date:
gnudate(){if hash gdate 2>/dev/null;then
gdate "$@"else
date "$@"fi}
@Geert: La parte &> / dev / null oculta el mensaje que 'type' emite cuando 'foo' no existe. El> & 2 en el eco se asegura de enviar el mensaje de error al error estándar en lugar de a la salida estándar; porque eso es convención. Ambos aparecen en su terminal, pero el error estándar es definitivamente la salida preferida para mensajes de error y advertencias inesperadas.
Para aquellos que no están familiarizados con la redirección de E / 2>&-S 'avanzada' en bash: 1) ("cerrar descriptor de archivo de salida 2", que es stderr) tiene el mismo resultado que 2> /dev/null; 2) >&2es un acceso directo para 1>&2, que puede reconocer como "redireccionar stdout a stderr". Consulte la página de redirección de E / S de la Guía avanzada de secuencias de comandos de Bash para obtener más información.
mikewaters
99
@mikewaters El ABS parece bastante avanzado y describe una amplia gama de funciones CLI bash y no bash, pero es muy negligente en muchos aspectos y no sigue las buenas prácticas. No tengo casi suficiente espacio en este comentario para escribir un artículo; pero puedo pegar algunos ejemplos al azar de código malo: while read element ; do .. done <<< $(echo ${ArrayVar[*]}), for word in $(fgrep -l $ORIGINAL *.txt), ls -l "$directory" | sed 1d , {{en un seq $BEGIN $END}}, ... Muchos han intentado ponerse en contacto con los autores y proponer mejoras pero no es wiki y solicitudes han aterrizado en oídos sordos.
Lunath
56
@mikewaters no2>&- es lo mismo que 2>/dev/null. El primero cierra el descriptor de archivo, mientras que el segundo simplemente lo redirige a /dev/null. Es posible que no vea un error porque el programa intenta informarle en stderr que stderr está cerrado.
nyuszika7h
577
La siguiente es una forma portátil de verificar si existe un comando $PATHy si es ejecutable:
[-x "$(command -v foo)"]
Ejemplo:
if![-x "$(command -v git)"];then
echo 'Error: git is not installed.'>&2
exit 1fi
La verificación ejecutable es necesaria porque bash devuelve un archivo no ejecutable si no se encuentra ningún archivo ejecutable con ese nombre $PATH.
También tenga en cuenta que si un archivo no ejecutable con el mismo nombre que el ejecutable existe anteriormente $PATH, el guión devuelve el primero, a pesar de que el último se ejecutaría. Esto es un error y viola el estándar POSIX. [ Informe de error ] [ Estándar ]
Además, esto fallará si el comando que está buscando se ha definido como un alias.
¿ command -vProducirá una ruta incluso para un archivo no ejecutable? Es decir, el -x realmente necesario?
einpoklum
55
@einpoklum -xprueba que el archivo es ejecutable, que es la pregunta.
Ken Sharp
3
@KenSharp: Pero eso parece ser redundante, ya que commandprobará si es ejecutable, ¿no?
einpoklum
13
@einpoklum Sí, es necesario. De hecho, incluso esta solución puede romperse en un caso extremo. Gracias por llamar mi atención sobre esto. dash, bash y zsh saltan todos los archivos no ejecutables $PATHal ejecutar un comando. Sin embargo, el comportamiento de command -ves muy inconsistente. En el guión, devuelve el primer archivo coincidente $PATH, independientemente de si es ejecutable o no. En bash, devuelve la primera coincidencia ejecutable $PATH, pero si no hay ninguna, puede devolver un archivo no ejecutable. Y en zsh, nunca devolverá un archivo no ejecutable.
nyuszika7h
55
Por lo que puedo decir, dashes el único de esos tres que no cumple con POSIX; [ -x "$(command -v COMMANDNAME)"]funcionará en los otros dos. Parece que este error ya se ha informado, pero aún no tiene respuestas: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
nyuszika7h
210
Estoy de acuerdo con lhunath para desalentar el uso de which, y su solución es perfectamente válida para los usuarios de Bash . Sin embargo, para ser más portátil, command -vse utilizará en su lugar:
$ command -v foo >/dev/null 2>&1||{ echo "I require foo but it's not installed. Aborting.">&2; exit 1;}
Igual que el anterior: exit 1;mata un xterm, si se invoca desde allí.
usuario desconocido
1
Esto no funcionaría en un sh estándar: you &> no es una instrucción de redireccionamiento válida.
jyavenard
77
@jyavenard: La pregunta está etiquetada como bash , de ahí la notación de redireccionamiento específica de bash más concisa &>/dev/null. Sin embargo, estoy de acuerdo con usted, lo que realmente importa es la portabilidad, he editado mi respuesta en consecuencia, ahora usando la redirección sh estándar >/dev/null 2>&1.
GregV
para mejorar aún más esta respuesta, haría dos cosas: 1: use "&>" para simplificarla, como la respuesta de Josh. 2: separe el {} en una línea adicional, colocando una pestaña antes del eco, para
&>Es posible que no esté disponible en su versión de Bash. El código de Marcello debería funcionar bien; hace la misma cosa.
Josh Strater
3
Falla en palabras incorporadas y palabras reservadas: intente esto con la palabra thenpor ejemplo. Vea esta respuesta si necesita que exista el ejecutable $PATH.
Tom Hale
84
Depende de si desea saber si existe en uno de los directorios de la $PATHvariable o si conoce la ubicación absoluta de la misma. Si desea saber si está en la $PATHvariable, use
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 whichprograma.
Realmente no deberías usar "which" por las razones descritas en mi comentario.
lhunath
39
Ampliando las respuestas de @ lhunath y @ GregV, aquí está el código para las personas que quieren poner fácilmente ese cheque dentro de una ifdeclaración:
exists(){
command -v "$1">/dev/null 2>&1}
Aquí se explica cómo usarlo:
if exists bash;then
echo 'Bash exists!'else
echo 'Your system does not have Bash'fi
La voluntad de aprender y mejorar debe ser recompensada. +1 Esto es limpio y simple. Lo único que puedo agregar es que commandtiene éxito incluso para los alias, que podrían ser algo contradictorios. Verificar la existencia en un shell interactivo dará resultados diferentes de cuando lo mueves a un script.
Palec
1
Acabo de probar y usar shopt -u expand_aliasesignorar / ocultar alias (como el alias ls='ls -F'mencionado en otra respuesta) y shopt -s expand_aliasesresolverlos a través de command -v. Entonces, tal vez debería establecerse antes de la verificación y desarmar después, aunque podría afectar el valor de retorno de la función si no captura y devuelve el resultado de la llamada de comando explícitamente.
hash foo &>/dev/null
if[ $?-eq 1];then
echo >&2"foo not found."fi
Este script se ejecuta hashy luego comprueba si el código de salida del comando más reciente, el valor almacenado $?, es igual a 1. Si hashno encuentra foo, el código de salida será 1. Si fooestá presente, el código de salida lo estará 0.
&> /dev/nullredirige el error estándar y la salida estándar de hashmodo que no aparezca en pantalla y echo >&2escribe el mensaje en error estándar.
¿Por qué no solo if hash foo &> /dev/null; then ...?
Beni Cherniavsky-Paskin
9
Nunca obtuve las respuestas anteriores para trabajar en el cuadro al que tengo acceso. Por un lado, typese ha instalado (haciendo lo que morehace). Por lo tanto, se necesita la directiva incorporada. Este comando funciona para mí:
if[`builtin type -p vim`];then echo "TRUE";else echo "FALSE";fi
Los corchetes no son parte de la ifsintaxis, simplemente use if builtin type -p vim; then .... Y los backticks son una sintaxis realmente antigua y obsoleta, $()incluso shen todos los sistemas modernos.
nyuszika7h
9
Compruebe si hay varias dependencias e informe el estado a los usuarios finales.
for cmd in latex pandoc;do
printf '%-10s'"$cmd"if hash "$cmd"2>/dev/null;then
echo OK
else
echo missing
fidone
Forma no detallada de hacerlo: 1) deshacerse del especificador de ancho; 2) agregue un espacio después del nombre de comando printf; 3) canalice su bucle for a column -t(parte de util-linux).
Patrice Levesque
8
Si verifica la existencia del programa, probablemente lo ejecutará más tarde de todos modos. ¿Por qué no intentar ejecutarlo en primer lugar?
if foo --version >/dev/null 2>&1;then
echo Foundelse
echo Not found
fi
Es un control más confiable que el programa se ejecuta que simplemente mirar directorios de RUTA y permisos de archivos.
Además, puede obtener algunos resultados útiles de su programa, como su versión.
Por supuesto, los inconvenientes son que algunos programas pueden ser pesados para comenzar y otros no tienen la --versionopción de salir inmediatamente (y con éxito).
tipo -P nombre del programa es preferible, ver respuesta aceptada
RobertG
@RobertG Todo lo que veo es que -Pno es POSIX. ¿Por qué se type -Pprefiere?
mikemaccana
Debería haber dicho "para ser preferido en entornos bash", ya que tenía la intención de responder el comentario anterior específico de bash. De todos modos, eso fue hace años, supongo que debería, nuevamente, señalarle la respuesta marcada como "aceptada"
RobertG
4
El comando -vfunciona bien si la opción POSIX_BUILTINS está establecida para<command> prueba, pero puede fallar si no. (Me ha funcionado durante años, pero recientemente me encontré con uno donde no funcionaba).
Encuentro que lo siguiente es más a prueba de fallas:
test -x $(which <command>)
Ya que prueba tres cosas: ruta, existencia y permiso de ejecución.
No funciona test -x $(which ls)devuelve 0, como lo hace test -x $(which sudo), aunque lsesté instalado y ejecutable y sudoni siquiera esté instalado dentro del contenedor acoplable en el que me estoy ejecutando.
algal
@algal Necesitas usar citas, creo, así quetest -x "$(which <command>)"
JoniVR
@algal Quizás lstiene un alias? No creo que funcione si el comando tiene parámetro.
AnthonyC
3
Para aquellos interesados, ninguna de las metodologías en las respuestas anteriores funciona si desea detectar una biblioteca instalada. Me imagino que te queda verificar físicamente la ruta (potencialmente para archivos de encabezado y demás), o algo así (si estás en una distribución basada en Debian):
Como puede ver en lo anterior, una respuesta "0" de la consulta significa que el paquete no está instalado. Esta es una función de "grep": un "0" significa que se encontró una coincidencia, un "1" significa que no se encontró ninguna coincidencia.
Yo diría que no hay ninguna forma portátil y 100% confiable debido a los colgantes alias. Por ejemplo:
alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/
Por supuesto, solo el último es problemático (¡sin ofender a Ringo!). Pero todos ellos son válidos aliasdesde el punto de vista de command -v.
Para rechazar los que cuelgan ringo, tenemos que analizar la salida del aliascomando incorporado de shell y recurrir a ellos ( command -vno es superior a aliasaquí). No hay ninguna solución portátil para ello, e incluso un Bash- La solución específica es bastante tediosa.
Tenga en cuenta que una solución como esta rechazará incondicionalmente alias ls='ls -F':
Devuelve 0 si se encuentra el ejecutable y devuelve 1 si no se encuentra o no es ejecutable:
NAME
which - locate a command
SYNOPSIS
which [-a] filename ...
DESCRIPTION
which returns the pathnames of the files which would
be executed in the current environment, had its
arguments been given as commands in a strictly
POSIX-conformant shell. It does this by searching
the PATH for executable files matching the names
of the arguments.
OPTIONS
-a print all matching pathnames of each argument
EXIT STATUS
0 if all specified commands are
found and executable
1 if one or more specified commands is nonexistent
or not executable
2 if an invalid option is specified
Lo bueno de esto whiches que determina si el ejecutable está disponible en el entorno en el que whichse ejecuta, ahorra algunos problemas ...
Use which si está buscando un ejecutable llamado foo, pero vea mi respuesta si desea verificar un archivo / ruta / a / a / named / foo en particular. También tenga en cuenta lo que puede no estar disponible en algunos sistemas mínimos, a pesar de que debería estar presente en cualquier instalación de pleno derecho ...
dmckee --- ex-moderador gatito
99
No confíe en el estado de salida del cual. Muchos sistemas operativos tienen uno que ni siquiera establece un estado de salida que no sea 0.
Si ustedes / chicas no pueden obtener las cosas en las respuestas aquí para trabajar y se están quitando el cabello de la espalda, intenten ejecutar el mismo comando usando bash -c . Solo mira este delirio somnambular. Esto es lo que realmente sucede cuando ejecuta $ (subcomando):
Primero. Puede darle resultados completamente diferentes.
$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"/bin/ls
Segundo. No puede darle ningún resultado en absoluto.
Las diferencias son causadas por la diferencia entre el modo interactivo y no interactivo del shell. Su ~ / .bashrc es de solo lectura cuando el shell no es de inicio de sesión e interactivo. Sin embargo, el segundo parece extraño, porque esto debe ser causado por una diferencia en la variable de entorno PATH, pero las subcapas heredan el entorno.
Palec
En mi caso .bashrctengo un [ -z "$PS1" ] && returnantecedente, # If not running interactively, don't do anythingasí que supongo que es una razón por la cual incluso el abastecimiento explícito de bashrc en modo no interactivo no ayuda. El problema puede solucionarse llamando a un script con un operador de punto ss64.com/bash/source.html , . ./script.shpero eso no es algo que uno quisiera recordar escribir cada vez.
user619271
1
Obtener scripts de aprovisionamiento que no se supone deben ser una mala idea. Todo lo que intentaba decir es que su respuesta tiene poco que ver con la pregunta que se hace y mucho que ver con Bash y su modo (no) interactivo.
Palec
Si explicara lo que está sucediendo en estos casos, sería una adición útil a una respuesta.
Palec
0
La variante hash tiene un inconveniente: en la línea de comando, por ejemplo, puede escribir
one_folder/process
tener proceso ejecutado. Para esto, la carpeta principal de one_folder debe estar en $ PATH . Pero cuando intentas hacer hash este comando, siempre tendrá éxito:
hash one_folder/process; echo $?# will always output '0'
"Para esto, la carpeta principal de one_folder debe estar en $PATH": esto es completamente inexacto. Intentalo. Para que esto funcione, one_folder debe estar en el directorio actual .
Comodín el
0
Secundo el uso de "command -v". Por ejemplo, así:
md=$(command -v mkdirhier); alias md=${md:=mkdir}# bash
emacs="$(command -v emacs) -nw"|| emacs=nano
alias e=$emacs
[[-z $(command -v jed)]]&& alias jed=$emacs
Tuve que verificar si Git estaba instalado como parte de la implementación de nuestro servidor CI . Mi último script Bash fue el siguiente (servidor Ubuntu):
if! builtin type -p git &>/dev/null;then
sudo apt-get -y install git-core
fi
El condicional es bastante inútil, modula el tiempo de inicio para ejecutar apt-get, ya que apt-get estará satisfecho y saldrá si git-core ya está instalado.
tripleee
3
Su tiempo de inicio no es insignificante, pero la motivación más importante es sudo: sin el condicional, siempre se detendría y solicitaría una contraseña (a menos que haya hecho un sudo recientemente). Por cierto, puede ser útil hacerlo sudo -p "Type your password to install missing git-core: "para que el mensaje no salga de la nada.
Beni Cherniavsky-Paskin
0
Para imitar Bash's type -P cmd, podemos usar el compatible con POSIX env -i type cmd 1>/dev/null 2>&1.
man env
# "The option '-i' causes env to completely ignore the environment it inherits."# In other words, there are no aliases or functions to be looked up by the type command.
ls(){ echo 'Hello, world!';}
ls
type ls
env -i type ls
cmd=ls
cmd=lsx
env -i type $cmd 1>/dev/null 2>&1||{ echo "$cmd not found"; exit 1;}
¿Por qué se está votando esto? ¿En qué sistemas funciona esto realmente para usted? typeParece que hay una builtinen la mayoría de conchas así que esto no puede trabajar porque envusos execvpque se ejecuten commandde manera commandque no puede ser una builtin(y el builtinsiempre se llevará a cabo dentro del mismo entorno). Esta falla para mí en bash, ksh93, zsh, busybox [a]shy dashtodos los cuales proporcionan typecomo una orden interna del shell.
Adrian Frühwirth
0
Si no hay ningún typecomando externo disponible (como se da por sentado aquí ), podemos usar POSIX compatible env -i sh -c 'type cmd 1>/dev/null 2>&1':
# Portable version of Bash's type -P cmd (without output on stdout)
typep(){
command -p env -i PATH="$PATH" sh -c '
export LC_ALL=C LANG=C
cmd="$1"
cmd="`type "$cmd" 2>/dev/null || { echo "error: command $cmd not found; exiting ..." 1>&2; exit 1; }`"
[ $? != 0 ] && exit 1
case "$cmd" in
*\ /*) exit 0;;
*) printf "%s\n" "error: $cmd" 1>&2; exit 1;;
esac
' _ "$1"|| exit 1}# Get your standard $PATH value#PATH="$(command -p getconf PATH)"
typep ls
typep builtin
typep ls-temp
Al menos en Mac OS X v10.6.8 (Snow Leopard) usando Bash 4.2.24 (2) command -v lsno coincide con un movido /bin/ls-temp.
En caso de que desee verificar si un programa existe y es realmente un programa, no un comando incorporado de Bash , entonces command, typey hashno son apropiados para la prueba, ya que todos devuelven el estado de salida 0 para los comandos integrados.
Por ejemplo, existe el programa de tiempo que ofrece más funciones que el comando incorporado de tiempo . Para verificar si el programa existe, sugeriría usarlo whichcomo en el siguiente ejemplo:
# First check if the time program exists
timeProg=`which time`if["$timeProg"=""]then
echo "The time program does not exist on this system."
exit 1fi# Invoke the time program
$timeProg --quiet -o result.txt -f "%S %U + p" du -sk ~
echo "Total CPU time: `dc -f result.txt` seconds"
rm result.txt
#!/bin/bash# Commands found in the hash table are checked for existence before being# executed and non-existence forces a normal PATH search.
shopt -s checkhash
function exists(){local mycomm=$1; shift ||return1
hash $mycomm 2>/dev/null || \
printf "\xe2\x9c\x98 [ABRT]: $mycomm: command does not exist\n";return1;}
readonly -f exists
exists notacmd
exists bash
hash
bash -c 'printf "Fin.\n"'
Resultado
✘[ABRT]: notacmd: command does not exist
hits command
0/usr/bin/bash
Fin.
if[`LANG=C type example 2>/dev/null|wc -l`=1];then echo exists;else echo "not exists";fi
o
if[`LANG=C type example 2>/dev/null|wc -l`=1];then
echo exists
else echo "not exists"fi
Utiliza el estado de eco de los programas integrados y de shell para la salida estándar y nada para el error estándar. Por otro lado, si no se encuentra un comando, solo muestra el estado como error estándar.
which
devuelve cierto para estos.type
sin argumentos, también devolverá verdadero para las palabras reservadas y los componentes integrados de shell. Si "programa" significa "ejecutable en$PATH
", vea esta respuesta .Respuestas:
Responder
POSIX compatible:
Para entornos específicos de Bash:
Explicación
Evitar
which
. No solo es un proceso externo que está iniciando por hacer muy poco (lo que significa que las funciones integradashash
,type
ocommand
son mucho más barato), también puede depender de las órdenes internas para hacer realidad lo que quiere, mientras que los efectos de los comandos externos pueden variar fácilmente de sistema a sistema.¿Por qué importa?
which
que ni siquiera establece un estado de salida , lo que significaif which foo
que ni siquiera funcionará allí y siempre informará quefoo
existe, incluso si no existe (tenga en cuenta que algunos shells POSIX parecen hacer esto parahash
).which
cosas personalizadas y malvadas como cambiar la salida o incluso conectarse al administrador de paquetes.Entonces, no lo uses
which
. En su lugar, use uno de estos:(Nota al margen menor: algunos sugerirán que
2>&-
es igual2>/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 su hash bang es,
/bin/sh
entonces debería preocuparse por lo que dice POSIX.type
yhash
los códigos de salida de POSIX no están terriblemente bien definidos, yhash
se ve que sale con éxito cuando el comando no existe (todavía no lo he vistotype
).command
POSIX define bien el estado de salida, por lo que probablemente sea el más seguro de usar.Si sus usos de guión
bash
sin embargo, las normas POSIX realmente no importa más y tantotype
yhash
se vuelven perfectamente seguro para su uso.type
ahora tiene-P
que buscar solo elPATH
yhash
tiene el efecto secundario de que la ubicación del comando se cambiará (para una búsqueda más rápida la próxima vez que lo use), lo que generalmente es algo bueno, ya que probablemente verifique su existencia para usarlo realmente .Como ejemplo simple, aquí hay una función que se ejecuta
gdate
si existe, de lo contrariodate
:fuente
2>&-
S 'avanzada' en bash: 1) ("cerrar descriptor de archivo de salida 2", que es stderr) tiene el mismo resultado que2> /dev/null
; 2)>&2
es un acceso directo para1>&2
, que puede reconocer como "redireccionar stdout a stderr". Consulte la página de redirección de E / S de la Guía avanzada de secuencias de comandos de Bash para obtener más información.while read element ; do .. done <<< $(echo ${ArrayVar[*]})
,for word in $(fgrep -l $ORIGINAL *.txt)
,ls -l "$directory" | sed 1d
, {{en unseq $BEGIN $END
}}, ... Muchos han intentado ponerse en contacto con los autores y proponer mejoras pero no es wiki y solicitudes han aterrizado en oídos sordos.2>&-
es lo mismo que2>/dev/null
. El primero cierra el descriptor de archivo, mientras que el segundo simplemente lo redirige a/dev/null
. Es posible que no vea un error porque el programa intenta informarle en stderr que stderr está cerrado.La siguiente es una forma portátil de verificar si existe un comando
$PATH
y si es ejecutable:Ejemplo:
La verificación ejecutable es necesaria porque bash devuelve un archivo no ejecutable si no se encuentra ningún archivo ejecutable con ese nombre
$PATH
.También tenga en cuenta que si un archivo no ejecutable con el mismo nombre que el ejecutable existe anteriormente
$PATH
, el guión devuelve el primero, a pesar de que el último se ejecutaría. Esto es un error y viola el estándar POSIX. [ Informe de error ] [ Estándar ]Además, esto fallará si el comando que está buscando se ha definido como un alias.
fuente
command -v
Producirá una ruta incluso para un archivo no ejecutable? Es decir, el -x realmente necesario?-x
prueba que el archivo es ejecutable, que es la pregunta.command
probará si es ejecutable, ¿no?$PATH
al ejecutar un comando. Sin embargo, el comportamiento decommand -v
es muy inconsistente. En el guión, devuelve el primer archivo coincidente$PATH
, independientemente de si es ejecutable o no. En bash, devuelve la primera coincidencia ejecutable$PATH
, pero si no hay ninguna, puede devolver un archivo no ejecutable. Y en zsh, nunca devolverá un archivo no ejecutable.dash
es el único de esos tres que no cumple con POSIX;[ -x "$(command -v COMMANDNAME)"]
funcionará en los otros dos. Parece que este error ya se ha informado, pero aún no tiene respuestas: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264Estoy de acuerdo con lhunath para desalentar el uso de
which
, y su solución es perfectamente válida para los usuarios de Bash . Sin embargo, para ser más portátil,command -v
se utilizará en su lugar:El comando
command
es compatible con POSIX. Consulte aquí su especificación: comando: ejecute un comando simpleNota:
type
es compatible con POSIX, perotype -P
no lo es.fuente
exit 1;
mata un xterm, si se invoca desde allí.&>/dev/null
. Sin embargo, estoy de acuerdo con usted, lo que realmente importa es la portabilidad, he editado mi respuesta en consecuencia, ahora usando la redirección sh estándar>/dev/null 2>&1
.Tengo una función definida en mi .bashrc que lo hace más fácil.
Aquí hay un ejemplo de cómo se usa (de mi
.bash_profile
).fuente
&>
?&>
redirige stdout y stderr juntos.&>
Es posible que no esté disponible en su versión de Bash. El código de Marcello debería funcionar bien; hace la misma cosa.then
por ejemplo. Vea esta respuesta si necesita que exista el ejecutable$PATH
.Depende de si desea saber si existe en uno de los directorios de la
$PATH
variable o si conoce la ubicación absoluta de la misma. Si desea saber si está en la$PATH
variable, usede lo contrario usar
La redirección a
/dev/null/
en el primer ejemplo suprime la salida delwhich
programa.fuente
Ampliando 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:Aquí se explica cómo usarlo:
fuente
command
tiene éxito incluso para los alias, que podrían ser algo contradictorios. Verificar la existencia en un shell interactivo dará resultados diferentes de cuando lo mueves a un script.shopt -u expand_aliases
ignorar / ocultar alias (como elalias ls='ls -F'
mencionado en otra respuesta) yshopt -s expand_aliases
resolverlos a través decommand -v
. Entonces, tal vez debería establecerse antes de la verificación y desarmar después, aunque podría afectar el valor de retorno de la función si no captura y devuelve el resultado de la llamada de comando explícitamente.Intenta usar:
o
Desde la página de manual de Bash en Expresiones condicionales :
fuente
Para usar
hash
, como sugiere @lhunath , en un script Bash:Este script se ejecuta
hash
y luego comprueba si el código de salida del comando más reciente, el valor almacenado$?
, es igual a1
. Sihash
no encuentrafoo
, el código de salida será1
. Sifoo
está presente, el código de salida lo estará0
.&> /dev/null
redirige el error estándar y la salida estándar dehash
modo que no aparezca en pantalla yecho >&2
escribe el mensaje en error estándar.fuente
if hash foo &> /dev/null; then ...
?Nunca obtuve las respuestas anteriores para trabajar en el cuadro al que tengo acceso. Por un lado,
type
se ha instalado (haciendo lo quemore
hace). Por lo tanto, se necesita la directiva incorporada. Este comando funciona para mí:fuente
if
sintaxis, simplemente useif builtin type -p vim; then ...
. Y los backticks son una sintaxis realmente antigua y obsoleta,$()
inclusosh
en todos los sistemas modernos.Compruebe si hay varias dependencias e informe el estado a los usuarios finales.
Salida de muestra:
Ajuste el
10
a la longitud máxima del comando. No es automático, porque no veo una forma POSIX no detallada de hacerlo: ¿Cómo puedo alinear las columnas de una tabla separada por espacios en Bash?Compruebe si algunos
apt
paquetes están instaladosdpkg -s
e instálelos de lo contrario .Consulte: Compruebe si hay instalado un paquete apt-get y luego instálelo si no está en Linux
Se mencionó anteriormente en: ¿Cómo puedo verificar si un programa existe desde un script Bash?
fuente
column -t
(parte de util-linux).Si verifica la existencia del programa, probablemente lo ejecutará más tarde de todos modos. ¿Por qué no intentar ejecutarlo en primer lugar?
Es un control más confiable que el programa se ejecuta que simplemente mirar directorios de RUTA y permisos de archivos.
Además, puede obtener algunos resultados útiles de su programa, como su versión.
Por supuesto, los inconvenientes son que algunos programas pueden ser pesados para comenzar y otros no tienen la
--version
opción de salir inmediatamente (y con éxito).fuente
hash foo 2>/dev/null
: funciona con Z shell (Zsh), Bash, Dash y ash .type -p foo
: parece funcionar con Z shell, Bash y ash ( BusyBox ), pero no con Dash (se interpreta-p
como un argumento).command -v foo
: funciona con Z shell, Bash, Dash, pero no ash (BusyBox) (-ash: command: not found
).También tenga en cuenta que
builtin
no está disponible con ceniza y tablero.fuente
Use Bash Builtins si puede:
...
fuente
which
No es un Bash incorporado.-P
no es POSIX. ¿Por qué setype -P
prefiere?El comando
-v
funciona bien si la opción POSIX_BUILTINS está establecida para<command>
prueba, pero puede fallar si no. (Me ha funcionado durante años, pero recientemente me encontré con uno donde no funcionaba).Encuentro que lo siguiente es más a prueba de fallas:
Ya que prueba tres cosas: ruta, existencia y permiso de ejecución.
fuente
test -x $(which ls)
devuelve 0, como lo hacetest -x $(which sudo)
, aunquels
esté instalado y ejecutable ysudo
ni siquiera esté instalado dentro del contenedor acoplable en el que me estoy ejecutando.test -x "$(which <command>)"
ls
tiene un alias? No creo que funcione si el comando tiene parámetro.Para aquellos interesados, ninguna de las metodologías en las respuestas anteriores funciona si desea detectar una biblioteca instalada. Me imagino que te queda verificar físicamente la ruta (potencialmente para archivos de encabezado y demás), o algo así (si estás en una distribución basada en Debian):
Como puede ver en lo anterior, una respuesta "0" de la consulta significa que el paquete no está instalado. Esta es una función de "grep": un "0" significa que se encontró una coincidencia, un "1" significa que no se encontró ninguna coincidencia.
fuente
cmd; if [ $? -eq 0 ]; then
debería ser refactorizadoif cmd; then
dpkg
oapt
Hay un montón de opciones aquí, pero no me sorprendió nada rápido. Esto es lo que usé al comienzo de mis scripts:
Esto se basa en la respuesta seleccionada aquí y en otra fuente.
fuente
Yo diría que no hay ninguna forma portátil y 100% confiable debido a los colgantes
alias
. Por ejemplo:Por supuesto, solo el último es problemático (¡sin ofender a Ringo!). Pero todos ellos son válidos
alias
desde el punto de vista decommand -v
.Para rechazar los que cuelgan
ringo
, tenemos que analizar la salida delalias
comando incorporado de shell y recurrir a ellos (command -v
no es superior aalias
aquí). No hay ninguna solución portátil para ello, e incluso un Bash- La solución específica es bastante tediosa.Tenga en cuenta que una solución como esta rechazará incondicionalmente
alias ls='ls -F'
:fuente
shopt -u expand_aliases
ignora / oculta estos alias y losshopt -s expand_aliases
muestra a través decommand -v
.Esto indicará según la ubicación si el programa existe o no:
fuente
El
which
comando puede ser útil.hombre queDevuelve 0 si se encuentra el ejecutable y devuelve 1 si no se encuentra o no es ejecutable:
Lo bueno de esto
which
es que determina si el ejecutable está disponible en el entorno en el quewhich
se ejecuta, ahorra algunos problemas ...fuente
Mi configuración para un Debian servidor :
Tuve el problema cuando varios paquetes contenían el mismo nombre.
Por ejemplo
apache2
. Entonces esta fue mi solución:fuente
Si ustedes / chicas no pueden obtener las cosas en las respuestas aquí para trabajar y se están quitando el cabello de la espalda, intenten ejecutar el mismo comando usando
bash -c
. Solo mira este delirio somnambular. Esto es lo que realmente sucede cuando ejecuta $ (subcomando):Primero. Puede darle resultados completamente diferentes.
Segundo. No puede darle ningún resultado en absoluto.
fuente
.bashrc
tengo un[ -z "$PS1" ] && return
antecedente,# If not running interactively, don't do anything
así que supongo que es una razón por la cual incluso el abastecimiento explícito de bashrc en modo no interactivo no ayuda. El problema puede solucionarse llamando a un script con un operador de punto ss64.com/bash/source.html ,. ./script.sh
pero eso no es algo que uno quisiera recordar escribir cada vez.La variante hash tiene un inconveniente: en la línea de comando, por ejemplo, puede escribir
tener proceso ejecutado. Para esto, la carpeta principal de one_folder debe estar en $ PATH . Pero cuando intentas hacer hash este comando, siempre tendrá éxito:
fuente
$PATH
": esto es completamente inexacto. Intentalo. Para que esto funcione, one_folder debe estar en el directorio actual .Secundo el uso de "command -v". Por ejemplo, así:
fuente
Tuve que verificar si Git estaba instalado como parte de la implementación de nuestro servidor CI . Mi último script Bash fue el siguiente (servidor Ubuntu):
fuente
sudo
: sin el condicional, siempre se detendría y solicitaría una contraseña (a menos que haya hecho un sudo recientemente). Por cierto, puede ser útil hacerlosudo -p "Type your password to install missing git-core: "
para que el mensaje no salga de la nada.Para imitar Bash's
type -P cmd
, podemos usar el compatible con POSIXenv -i type cmd 1>/dev/null 2>&1
.fuente
type
Parece que hay unabuiltin
en la mayoría de conchas así que esto no puede trabajar porqueenv
usosexecvp
que se ejecutencommand
de maneracommand
que no puede ser unabuiltin
(y elbuiltin
siempre se llevará a cabo dentro del mismo entorno). Esta falla para mí enbash
,ksh93
,zsh
,busybox [a]sh
ydash
todos los cuales proporcionantype
como una orden interna del shell.Si no hay ningún
type
comando externo disponible (como se da por sentado aquí ), podemos usar POSIX compatibleenv -i sh -c 'type cmd 1>/dev/null 2>&1'
:Al menos en Mac OS X v10.6.8 (Snow Leopard) usando Bash 4.2.24 (2)
command -v ls
no coincide con un movido/bin/ls-temp
.fuente
En caso de que desee verificar si un programa existe y es realmente un programa, no un comando incorporado de Bash , entonces
command
,type
yhash
no son apropiados para la prueba, ya que todos devuelven el estado de salida 0 para los comandos integrados.Por ejemplo, existe el programa de tiempo que ofrece más funciones que el comando incorporado de tiempo . Para verificar si el programa existe, sugeriría usarlo
which
como en el siguiente ejemplo:fuente
Quería que se respondiera la misma pregunta pero que se ejecutara dentro de un Makefile.
fuente
Guión
Resultado
fuente
Yo uso esto, porque es muy fácil:
o
Utiliza el estado de eco de los programas integrados y de shell para la salida estándar y nada para el error estándar. Por otro lado, si no se encuentra un comando, solo muestra el estado como error estándar.
fuente