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

2212

¿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 estado confundiendo.

gregh
fuente
¿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 .
Tom Hale

Respuestas:

3056

Responder

POSIX compatible:

command -v <the_command>

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á 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
}
lhunath
fuente
35
@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.
lhunath
55
el indicador -P no funciona en 'sh', por ejemplo stackoverflow.com/questions/2608688/…
momeara el
130
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 $PATH y si 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 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.

nyuszika7h
fuente
44
¿ 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; }

El comando commandes compatible con POSIX. Consulte aquí su especificación: comando: ejecute un comando simple

Nota: typees compatible con POSIX, pero type -Pno lo es.

GregV
fuente
3
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
facilitar la
Acabo de poner este un trazador de líneas en una función de bash si alguien lo quiere ... github.com/equant/my_bash_tools/blob/master/tarp.bash
equant
94

Tengo una función definida en mi .bashrc que lo hace 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
Josh Strater
fuente
¿Qué hace el &>?
Saad Malik
77
El &> redirige stdout y stderr juntos.
Josh Strater
&>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.

dreamlax
fuente
22
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
Romário
fuente
13
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.
dragon788
24

Intenta usar:

test -x filename

o

[ -x filename ]

Desde la página de manual de Bash en Expresiones condicionales :

 -x file
          True if file exists and is executable.
dmckee --- gatito ex moderador
fuente
26
Eso significa que ya necesita conocer la ruta completa a la aplicación.
lhunath
12
El OP no especificó si quería verificar una instancia específica o cualquier instancia ejecutable ... Respondí de la forma en que la leí.
dmckee --- ex-gatito moderador
16

Para usar hash, como sugiere @lhunath , en un script Bash:

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.

dcharles
fuente
8
¿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
Magnus
fuente
3
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
  fi
done

Salida de muestra:

latex     OK
pandoc    missing

Ajuste el 10a 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 aptpaquetes están instalados dpkg -se 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?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
1
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 Found
else
    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).

0xF
fuente
6

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 -pcomo 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 builtinno está disponible con ceniza y tablero.

azulado
fuente
4

Use Bash Builtins si puede:

which programname

...

type -P programname
Peter Mortensen
fuente
15
¿Eh? whichNo es un Bash incorporado.
tripleee
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.

AnthonyC
fuente
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):

dpkg --status libdb-dev | grep -q not-installed

if [ $? -eq 0 ]; then
    apt-get install libdb-dev
fi

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.

Nathan Crause
fuente
10
Sin embargo, el antipatrón cmd; if [ $? -eq 0 ]; thendebería ser refactorizadoif cmd; then
tripleee
Esto solo funciona para bibliotecas instaladas a través de dpkgoapt
Weijun Zhou
3

Hay un montón de opciones aquí, pero no me sorprendió nada rápido. Esto es lo que usé al comienzo de mis scripts:

[[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; }
[[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }

Esto se basa en la respuesta seleccionada aquí y en otra fuente.

keisar
fuente
2

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':

test() { command -v $1 | grep -qv alias }
nodakai
fuente
Buen punto. Sin embargo, cuando se ejecuta desde un script bash, los alias no son visibles.
Basil Musa
1
También hay un problema, devolverá falso cuando se marca el comando 'alias'. Cuando debería volver cierto. Ejemplo: prueba "alias"
Basil Musa
2
Acabo de probar y usar shopt -u expand_aliasesignora / oculta estos alias y los shopt -s expand_aliasesmuestra a través de command -v.
dragon788
2

Esto indicará según la ubicación si el programa existe o no:

    if [ -x /usr/bin/yum ]; then
        echo "This is Centos"
    fi
Klevin Kona
fuente
Sí, agregué este comando si necesita instalar un paquete en el servidor, Abrir suse, centos, Debian
Klevin Kona
El resaltado de sintaxis está desactivado en la línea "echo". ¿Cuál es la solución? ¿Sugiere que el script Bash debería ser diferente?
Peter Mortensen
@PeterMortensen El resaltado de sintaxis está desactivado porque no reconoce que es una cadena.
Adrien
1

El whichcomando puede ser útil.hombre que

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 ...

Adam Davis
fuente
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.
lhunath
1

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:

function _apt_install() {
    apt-get install -y $1 > /dev/null
}

function _apt_install_norecommends() {
    apt-get install -y --no-install-recommends $1 > /dev/null
}
function _apt_available() {
    if [ `apt-cache search $1 | grep -o "$1" | uniq | wc -l` = "1" ]; then
        echo "Package is available : $1"
        PACKAGE_INSTALL="1"
    else
        echo "Package $1 is NOT available for install"
        echo  "We can not continue without this package..."
        echo  "Exitting now.."
        exit 0
    fi
}
function _package_install {
    _apt_available $1
    if [ "${PACKAGE_INSTALL}" = "1" ]; then
        if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
             echo  "package is already_installed: $1"
        else
            echo  "installing package : $1, please wait.."
            _apt_install $1
            sleep 0.5
        fi
    fi
}

function _package_install_no_recommends {
    _apt_available $1
    if [ "${PACKAGE_INSTALL}" = "1" ]; then
        if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
             echo  "package is already_installed: $1"
        else
            echo  "installing package : $1, please wait.."
            _apt_install_norecommends $1
            sleep 0.5
        fi
    fi
}
ThCTLo
fuente
1

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.

$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found
usuario619271
fuente
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'
anycast.cw
fuente
44
"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
usuario2961933
fuente
0

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
Greg K
fuente
3
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; }
tim
fuente
77
¿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.

freno
fuente
0

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 1
fi

# 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
rpr
fuente
0

Quería que se respondiera la misma pregunta pero que se ejecutara dentro de un Makefile.

install:
    @if [[ ! -x "$(shell command -v ghead)" ]]; then \
        echo 'ghead does not exist. Please install it.'; \
        exit -1; \
    fi
Richard A Quadling
fuente
-1

Guión

#!/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 || return 1

 hash $mycomm 2>/dev/null || \
 printf "\xe2\x9c\x98 [ABRT]: $mycomm: command does not exist\n"; return 1;
}
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.
ecwpz91
fuente
-1

Yo uso esto, porque es muy fácil:

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.

UN
fuente