O que é um "programa"? Inclui funções e aliases? whichretorna verdadeiro para estes. typesem argumentos também retornará true para palavras reservadas e embutidos no shell. Se "programa" significa "permutável em $PATH", consulte esta resposta .
hash <the_command># For regular commands. Or...
type <the_command># To check built-ins and keywords
Explicação
Evite which. Não só é um processo externo você está lançando para fazer muito pouco (ou seja, builtins gosto hash, typeou commandestão muito mais barato), você também pode contar com os builtins para realmente fazer o que quiser, enquanto os efeitos dos comandos externos podem facilmente variar de sistema para sistema.
Por que se importar?
Muitos sistemas operacionais possuem um statuswhich que nem define um status de saída , o que significa que if which fooele nem funciona lá e sempre informa que fooexiste, mesmo que não exista (observe que alguns shells POSIX parecem fazer isso hashtambém).
Muitos sistemas operacionais fazem whichcoisas personalizadas e más, como alterar a saída ou até se conectar ao gerenciador de pacotes.
Então, não use which. Em vez disso, use um destes:
$ 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 secundária secundária: alguns sugerem que 2>&-é o mesmo, 2>/dev/nullmas mais curto - isso é falso . 2>&-Fecha o FD 2, que causa um erro no programa ao tentar gravar no stderr, que é muito diferente de gravar com sucesso e descartar a saída (e perigoso!))
Se o seu hash bang for /bin/sh, você deve se preocupar com o que o POSIX diz. typee hash's códigos de saída não são terrivelmente bem definido pela POSIX, e hashé visto para sair com êxito quando o comando não existe (não vi isso com typeainda). commandO status de saída é bem definido pelo POSIX, de modo que provavelmente é o mais seguro de usar.
Se o seu script usar bash, as regras do POSIX não importam mais e as duas typee hashse tornam perfeitamente seguras. typeagora tem -Pque procurar apenas PATHoehash tem o efeito colateral que a localização do comando será hash (para mais rápido lookup próxima vez que você usá-lo), que normalmente é uma coisa boa, pois você provavelmente verificar a sua existência, a fim de realmente usá-lo .
Como um exemplo simples, aqui está uma função que é executada gdatese existir, caso contrário date:
gnudate(){if hash gdate 2>/dev/null;then
gdate "$@"else
date "$@"fi}
@ Geert: A parte &> / dev / null oculta a mensagem 'type' emitida quando 'foo' não existe. O> & 2 no eco certifica-se de enviar a mensagem de erro ao erro padrão em vez da saída padrão; porque isso é convenção. Ambos aparecem no seu terminal, mas o erro padrão é definitivamente a saída preferida para mensagens de erro e avisos inesperados.
Para aqueles que não estão familiarizados com o redirecionamento de E / S 'avançado' no bash: 1) 2>&-("fechar o descritor de arquivo de saída 2", que é stderr) tem o mesmo resultado que 2> /dev/null; 2) >&2é um atalho para o 1>&2qual você pode reconhecer como "redirecionar stdout para stderr". Consulte a página de redirecionamento de E / S do Advanced Bash Scripting Guide para obter mais informações.
Mikewaters
9
@mikewaters O ABS parece bastante avançado e descreve uma ampla variedade de funcionalidades de CLI bash e não bash, mas é muito negligente em muitos aspectos e não segue as boas práticas. Não tenho espaço suficiente neste comentário para fazer uma redação; mas eu pode colar alguns exemplos aleatórios de código BAD: while read element ; do .. done <<< $(echo ${ArrayVar[*]}), for word in $(fgrep -l $ORIGINAL *.txt), ls -l "$directory" | sed 1d , {{para uma em seq $BEGIN $END}}, ... Muitos têm tentado entrar em contato com os autores e propor melhorias, mas não é nenhuma wiki e solicitações de ter desembarcado em ouvidos surdos.
Lhunath
56
@mikewaters não2>&- é o mesmo que . O primeiro fecha o descritor de arquivo, enquanto o último simplesmente o redireciona para . Você pode não ver um erro porque o programa tenta informá-lo no stderr que o stderr está fechado. 2>/dev/null/dev/null
precisa saber é o seguinte
577
A seguir, é uma maneira portátil de verificar se um comando existe $PATHe é executável:
[-x "$(command -v foo)"]
Exemplo:
if![-x "$(command -v git)"];then
echo 'Error: git is not installed.'>&2
exit 1fi
A verificação do executável é necessária porque o bash retorna um arquivo não executável se nenhum arquivo executável com esse nome for encontrado $PATH.
Observe também que, se um arquivo não executável com o mesmo nome do executável existir anteriormente $PATH, o dash retornará o anterior, mesmo que o último fosse executado. Este é um erro e viola o padrão POSIX. [ Relatório de erro ] [ Padrão ]
Além disso, isso falhará se o comando que você está procurando tiver sido definido como um alias.
Irá command -vproduzir um caminho mesmo para um arquivo não executável? Ou seja, o -x é realmente necessário?
einpoklum
5
O @einpoklum -xtesta se o arquivo é executável, e era essa a pergunta.
Ken afiada
3
@KenSharp: Mas isso parece ser redundante, já que commandele próprio testará se é executável - não é?
einpoklum
13
@einpoklum Sim, é necessário. De fato, mesmo essa solução pode quebrar em um único caso. Obrigado por trazer isso à minha atenção. dash, bash e zsh todos pulam sobre arquivos não executáveis $PATHao executar um comando. No entanto, o comportamento de command -vé muito inconsistente. No traço, ele retorna o primeiro arquivo correspondente $PATH, independentemente de ser executável ou não. No bash, ele retorna a primeira correspondência executável $PATH, mas, se não houver, pode retornar um arquivo não executável. E no zsh, ele nunca retornará um arquivo não executável.
nyuszika7h
5
Até onde eu sei, dashé o único desses três que não é compatível com POSIX; [ -x "$(command -v COMMANDNAME)"]vai funcionar nos outros dois. Parece que este bug já foi relatado, mas não tem todas as respostas ainda: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
nyuszika7h
210
Eu concordo com lhunath em desencorajar o uso de which, e sua solução é perfeitamente válida para usuários do Bash . No entanto, para ser mais portátil, command -vdeve ser usado:
$ command -v foo >/dev/null 2>&1||{ echo "I require foo but it's not installed. Aborting.">&2; exit 1;}
O mesmo que acima - exit 1;mata um xterm, se invocado a partir daí.
usuário desconhecido
1
Isso não funcionaria em um sh padrão: você não é uma instrução de redirecionamento válida.
precisa saber é o seguinte
7
@ jyavenard: A pergunta é marcada como bash , daí a notação de redirecionamento mais concisa e específica para o bash &>/dev/null. No entanto, eu concordo com você, o que realmente importa é a portabilidade, editei minha resposta de acordo, agora usando o redirecionamento sh padrão >/dev/null 2>&1.
GregV
para melhorar ainda mais essa resposta, eu faria duas coisas: 1: use "&>" para simplificá-la, como a resposta de Josh. 2: quebrar o {} em uma linha extra, colocando um separador antes do eco, para facilitar a leitura
&>pode não estar disponível na sua versão do Bash. O código de Marcello deve funcionar bem; faz a mesma coisa.
Josh Strater
3
Falha nas palavras incorporadas e reservadas: tente isso com a palavra then por exemplo. Veja esta resposta se você precisar que o executável exista $PATH.
Tom Hale
84
Depende se você deseja saber se ele existe em um dos diretórios da $PATHvariável ou se você sabe a localização absoluta dele. Se você quiser saber se está na $PATHvariável, use
if which programname >/dev/null;then
echo exists
else
echo does not exist
fi
caso contrário, use
if[-x /path/to/programname ];then
echo exists
else
echo does not exist
fi
O redirecionamento para /dev/null/no primeiro exemplo suprime a saída do whichprograma.
A vontade de aprender e melhorar deve ser recompensada. +1 Isso é limpo e simples. A única coisa que posso acrescentar é que é commandbem-sucedida mesmo para pseudônimos, o que pode ser um pouco contra-intuitivo. A verificação da existência em um shell interativo fornecerá resultados diferentes de quando você o move para um script.
Palec 12/12
1
Acabei de testar e usar shopt -u expand_aliasesignora / oculta aliases (como o alias ls='ls -F'mencionado em outra resposta) e os shopt -s expand_aliasesresolvo via command -v. Portanto, talvez ele deva ser definido antes da verificação e desmarcado depois, embora possa afetar o valor de retorno da função se você não capturar e retornar a saída da chamada de comando explicitamente.
hash foo &>/dev/null
if[ $?-eq 1];then
echo >&2"foo not found."fi
Esse script é executado hashe verifica se o código de saída do comando mais recente, o valor armazenado em$? , é igual a 1. Se hashnão encontrar foo, o código de saída será 1. Se fooestiver presente, o código de saída será 0.
&> /dev/nullredireciona o erro padrão e a saída padrão dehash modo que ele não aparece na tela eecho >&2 escreve a mensagem para o erro padrão.
Por que não apenas if hash foo &> /dev/null; then ...?
Beni Cherniavsky-Paskin
9
Eu nunca recebi as respostas anteriores para trabalhar na caixa a que tenho acesso. Por um lado, typefoi instalado (fazendo o que morefaz). Portanto, a diretiva integrada é necessária. Este comando funciona para mim:
if[`builtin type -p vim`];then echo "TRUE";else echo "FALSE";fi
Os colchetes não fazem parte da ifsintaxe, basta usar if builtin type -p vim; then .... E os backticks são realmente antigos e têm uma sintaxe obsoleta, e $()são suportados mesmo shem todos os sistemas modernos.
precisa saber é o seguinte
9
Verifique várias dependências e informe o status aos usuários finais
for cmd in latex pandoc;do
printf '%-10s'"$cmd"if hash "$cmd"2>/dev/null;then
echo OK
else
echo missing
fidone
Maneira não-detalhada de fazer isso: 1) livrar-se do especificador de largura; 2) adicione um espaço após o nome do seu comando printf; 3) canalize seu loop for para column -t(parte do util-linux).
Patrice Levesque 22/02
8
Se você verificar a existência do programa, provavelmente o executará mais tarde. Por que não tentar executá-lo em primeiro lugar?
if foo --version >/dev/null 2>&1;then
echo Foundelse
echo Not found
fi
É uma verificação mais confiável que o programa é executado do que apenas olhar para diretórios PATH e permissões de arquivo.
Além disso, você pode obter algum resultado útil do seu programa, como a versão.
Obviamente, os inconvenientes são que alguns programas podem ser pesados para iniciar e outros não têm a --versionopção de sair imediatamente (e com êxito).
digite programname -P deve ser preferida, ver resposta aceite
RobertG
@RobertG Tudo o que vejo é que -Pnão é POSIX. Por que é type -Ppreferido?
Mikemaccana #
Eu deveria ter formulado que "ser preferido em ambientes do bash" - como pretendia responder ao comentário anterior específico do bash. De qualquer forma, isso foi há anos atrás - acho que devo apenas apontar novamente para a resposta marcada como "aceita"
RobertG
4
O comando -vfunciona bem se a opção POSIX_BUILTINS estiver configurada para o<command> teste, mas poderá falhar se não. (Ele funcionou para mim por anos, mas recentemente encontrei um em que não funcionava.)
Considero o seguinte mais à prova de falhas:
test -x $(which <command>)
Uma vez que ele testa três coisas: permissão de caminho, existência e execução.
Não funciona test -x $(which ls)retorna 0, como o faz test -x $(which sudo), mesmo que lsesteja instalado e executável e sudonem sequer é instalado dentro do recipiente estivador eu estou correndo.
@algal Maybe ls seja um alias? Eu não acho que funcionaria se o comando tem parâmetro.
AnthonyC
3
Para os interessados, nenhuma das metodologias das respostas anteriores funciona se você deseja detectar uma biblioteca instalada. Eu imagino que você fique com a verificação física do caminho (potencialmente para arquivos de cabeçalho e outros), ou algo assim (se você estiver em uma distribuição baseada no Debian):
Como você pode ver acima, uma resposta "0" da consulta significa que o pacote não está instalado. Esta é uma função do "grep" - um "0" significa que uma correspondência foi encontrada, um "1" significa que nenhuma correspondência foi encontrada.
Eu diria que não existe uma maneira portátil e 100% confiável devido a oscilações aliases. Por exemplo:
alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/
Obviamente, apenas o último é problemático (sem ofensa a Ringo!). Mas todos eles são válidos aliasdo ponto de vista de command -v.
Para rejeitar outros pendentes ringo, precisamos analisar a saída do aliascomando interno do shell e recursá-los ( command -vnão é superior a aliasaqui.) Não existe uma solução portátil para isso, e até mesmo um Bash- solução específica é bastante entediante.
Observe que uma solução como essa rejeitará incondicionalmente alias ls='ls -F':
Retorna 0 se o executável for encontrado e retorna 1 se não for encontrado ou não é executável:
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
O bom whiché que ele descobre se o executável está disponível no ambiente em que whiché executado - ele economiza alguns problemas ...
Use what se estiver procurando por um executável chamado foo, mas veja minha resposta se quiser verificar um arquivo / caminho / para / a / named / foo em particular. Observe também que o que pode não estar disponível em alguns sistemas mínimos, embora deva estar presente em qualquer instalação de pleno direito ...
dmckee --- ex-moderador gatinho
9
Não confie no status de saída. Muitos sistemas operacionais têm uma que que nem sequer definir um status de saída diferente de 0.
Se vocês não conseguem obter as respostas aqui para o trabalho e estão arrancando os cabelos das costas, tente executar o mesmo comando usando bash -c. Basta olhar para esse delírio somnambular. Isto é o que realmente acontece quando você executa $ (subcomando):
Primeiro. Pode fornecer uma saída completamente diferente.
$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"/bin/ls
As diferenças são causadas pela diferença entre o modo interativo e não interativo do shell. Seu ~ / .bashrc é somente leitura quando o shell não é de login e é interativo. O segundo parece estranho, porque isso deve ser causado por uma diferença na variável de ambiente PATH, mas os subshells herdam o ambiente.
Palec 26/08/15
No meu caso, .bashrctenho um [ -z "$PS1" ] && returnprefixo, # If not running interactively, don't do anythingentão acho que essa é uma razão pela qual nem o fornecimento explícito de bashrc no modo não interativo não ajuda. O problema pode ser contornado chamando um script com um operador de ponto ss64.com/bash/source.html , . ./script.shmas isso não é algo que você gostaria de lembrar de digitar toda vez.
user619271
1
Scripts de fornecimento que não devem ser adquiridos é uma má ideia. Tudo o que eu estava tentando dizer é que sua resposta tem pouco a ver com a pergunta que está sendo feita e muito a ver com o Bash e seu modo (não) interativo.
Palec 26/08/15
Se explicasse o que está acontecendo nesses casos, seria um adendo útil a uma resposta.
Palec 26/08/15
0
A variante hash tem uma armadilha: na linha de comando, você pode, por exemplo, digitar
one_folder/process
ter processo executado. Para isso, a pasta pai da pasta one_folder deve estar em $ PATH . Mas quando você tenta fazer o hash deste comando, ele sempre será bem-sucedido:
hash one_folder/process; echo $?# will always output '0'
"Para isso, a pasta pai da pasta one_folder deve estar em $PATH" - isso é completamente impreciso. Tente. Para que isso funcione, a pasta one_folder deve estar no diretório atual .
Curinga
0
Eu segundo o uso do "comando -v". Por exemplo:
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
O condicional é bastante inútil, modulo o tempo de inicialização para executar o apt-get, pois o apt-get será satisfeito e sairá se o git-core já estiver instalado.
tripleee
3
Seu tempo de inicialização não é desprezível, mas a motivação mais importante é sudo: sem o condicional, ele sempre parava e solicita a senha (a menos que você tenha feito um sudo recentemente). BTW, pode ser útil fazê- sudo -p "Type your password to install missing git-core: "lo para que o prompt não saia do nada.
Home
0
Para imitar o Bash type -P cmd, podemos usar o compatível com 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 que isso está sendo votado? Em quais sistemas isso realmente funciona para você? typeparece ser um builtinna maioria das conchas de modo que este não pode trabalhar porque envusos execvppara executar commandde modo commandnão pode ser um builtin(eo builtinserá sempre executado dentro do mesmo ambiente). Esta falha para mim bash, ksh93, zsh, busybox [a]she dashtodos os quais fornecem typecomo um builtin shell.
Adrian Frühwirth
0
Se não houver nenhum typecomando externo disponível (como concedido aqui ), podemos usar o POSIX compatível 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
Pelo menos no Mac OS X 10.6.8 (Snow Leopard) usando o Bash 4.2.24 (2) command -v lsnão corresponde a um movimento /bin/ls-temp.
Caso você queira verificar se um programa existe e é realmente um programa, não um comando interno do Bash , então command, typeehash não são adequados para testar como eles todo o retorno 0 status de saída para built-in comandos.
Por exemplo, existe o programa de horário que oferece mais recursos do que o comando interno de horário . Para verificar se o programa existe, sugiro usar whichcomo no exemplo a seguir:
# 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
ou
if[`LANG=C type example 2>/dev/null|wc -l`=1];then
echo exists
else echo "not exists"fi
Ele usa o status de eco dos programas incorporados e do shell na saída padrão e nada no erro padrão. Por outro lado, se um comando não for encontrado, ele faz eco do status apenas para erro padrão.
which
retorna verdadeiro para estes.type
sem argumentos também retornará true para palavras reservadas e embutidos no shell. Se "programa" significa "permutável em$PATH
", consulte esta resposta .Respostas:
Responda
Compatível com POSIX:
Para ambientes específicos do Bash:
Explicação
Evite
which
. Não só é um processo externo você está lançando para fazer muito pouco (ou seja, builtins gostohash
,type
oucommand
estão muito mais barato), você também pode contar com os builtins para realmente fazer o que quiser, enquanto os efeitos dos comandos externos podem facilmente variar de sistema para sistema.Por que se importar?
which
que nem define um status de saída , o que significa queif which foo
ele nem funciona lá e sempre informa quefoo
existe, mesmo que não exista (observe que alguns shells POSIX parecem fazer issohash
também).which
coisas personalizadas e más, como alterar a saída ou até se conectar ao gerenciador de pacotes.Então, não use
which
. Em vez disso, use um destes:(Nota secundária secundária: alguns sugerem que
2>&-
é o mesmo,2>/dev/null
mas mais curto - isso é falso .2>&-
Fecha o FD 2, que causa um erro no programa ao tentar gravar no stderr, que é muito diferente de gravar com sucesso e descartar a saída (e perigoso!))Se o seu hash bang for
/bin/sh
, você deve se preocupar com o que o POSIX diz.type
ehash
's códigos de saída não são terrivelmente bem definido pela POSIX, ehash
é visto para sair com êxito quando o comando não existe (não vi isso comtype
ainda).command
O status de saída é bem definido pelo POSIX, de modo que provavelmente é o mais seguro de usar.Se o seu script usar
bash
, as regras do POSIX não importam mais e as duastype
ehash
se tornam perfeitamente seguras.type
agora tem-P
que procurar apenasPATH
oehash
tem o efeito colateral que a localização do comando será hash (para mais rápido lookup próxima vez que você usá-lo), que normalmente é uma coisa boa, pois você provavelmente verificar a sua existência, a fim de realmente usá-lo .Como um exemplo simples, aqui está uma função que é executada
gdate
se existir, caso contráriodate
:fonte
2>&-
("fechar o descritor de arquivo de saída 2", que é stderr) tem o mesmo resultado que2> /dev/null
; 2)>&2
é um atalho para o1>&2
qual você pode reconhecer como "redirecionar stdout para stderr". Consulte a página de redirecionamento de E / S do Advanced Bash Scripting Guide para obter mais informações.while read element ; do .. done <<< $(echo ${ArrayVar[*]})
,for word in $(fgrep -l $ORIGINAL *.txt)
,ls -l "$directory" | sed 1d
, {{para uma emseq $BEGIN $END
}}, ... Muitos têm tentado entrar em contato com os autores e propor melhorias, mas não é nenhuma wiki e solicitações de ter desembarcado em ouvidos surdos.2>&-
é o mesmo que . O primeiro fecha o descritor de arquivo, enquanto o último simplesmente o redireciona para . Você pode não ver um erro porque o programa tenta informá-lo no stderr que o stderr está fechado.2>/dev/null
/dev/null
A seguir, é uma maneira portátil de verificar se um comando existe
$PATH
e é executável:Exemplo:
A verificação do executável é necessária porque o bash retorna um arquivo não executável se nenhum arquivo executável com esse nome for encontrado
$PATH
.Observe também que, se um arquivo não executável com o mesmo nome do executável existir anteriormente
$PATH
, o dash retornará o anterior, mesmo que o último fosse executado. Este é um erro e viola o padrão POSIX. [ Relatório de erro ] [ Padrão ]Além disso, isso falhará se o comando que você está procurando tiver sido definido como um alias.
fonte
command -v
produzir um caminho mesmo para um arquivo não executável? Ou seja, o -x é realmente necessário?-x
testa se o arquivo é executável, e era essa a pergunta.command
ele próprio testará se é executável - não é?$PATH
ao executar um comando. No entanto, o comportamento decommand -v
é muito inconsistente. No traço, ele retorna o primeiro arquivo correspondente$PATH
, independentemente de ser executável ou não. No bash, ele retorna a primeira correspondência executável$PATH
, mas, se não houver, pode retornar um arquivo não executável. E no zsh, ele nunca retornará um arquivo não executável.dash
é o único desses três que não é compatível com POSIX;[ -x "$(command -v COMMANDNAME)"]
vai funcionar nos outros dois. Parece que este bug já foi relatado, mas não tem todas as respostas ainda: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264Eu concordo com lhunath em desencorajar o uso de
which
, e sua solução é perfeitamente válida para usuários do Bash . No entanto, para ser mais portátil,command -v
deve ser usado:O comando
command
é compatível com POSIX. Veja aqui para sua especificação: command - executa um comando simplesNota:
type
é compatível com POSIX, mastype -P
não é.fonte
exit 1;
mata um xterm, se invocado a partir daí.&>/dev/null
. No entanto, eu concordo com você, o que realmente importa é a portabilidade, editei minha resposta de acordo, agora usando o redirecionamento sh padrão>/dev/null 2>&1
.Eu tenho uma função definida no meu .bashrc que facilita isso.
Aqui está um exemplo de como é usado (do meu
.bash_profile
.)fonte
&>
faz?&>
redireciona stdout e stderr juntos.&>
pode não estar disponível na sua versão do Bash. O código de Marcello deve funcionar bem; faz a mesma coisa.then
por exemplo. Veja esta resposta se você precisar que o executável exista$PATH
.Depende se você deseja saber se ele existe em um dos diretórios da
$PATH
variável ou se você sabe a localização absoluta dele. Se você quiser saber se está na$PATH
variável, usecaso contrário, use
O redirecionamento para
/dev/null/
no primeiro exemplo suprime a saída dowhich
programa.fonte
Expandindo as respostas de @ lhunath e @ GregV, eis o código para as pessoas que desejam colocar facilmente essa verificação em uma
if
declaração:Veja como usá-lo:
fonte
command
bem-sucedida mesmo para pseudônimos, o que pode ser um pouco contra-intuitivo. A verificação da existência em um shell interativo fornecerá resultados diferentes de quando você o move para um script.shopt -u expand_aliases
ignora / oculta aliases (como oalias ls='ls -F'
mencionado em outra resposta) e osshopt -s expand_aliases
resolvo viacommand -v
. Portanto, talvez ele deva ser definido antes da verificação e desmarcado depois, embora possa afetar o valor de retorno da função se você não capturar e retornar a saída da chamada de comando explicitamente.Tente usar:
ou
Na página de manual do Bash, em Expressões condicionais :
fonte
Para usar
hash
, como sugere @lhunath , em um script Bash:Esse script é executado
hash
e verifica se o código de saída do comando mais recente, o valor armazenado em$?
, é igual a1
. Sehash
não encontrarfoo
, o código de saída será1
. Sefoo
estiver presente, o código de saída será0
.&> /dev/null
redireciona o erro padrão e a saída padrão dehash
modo que ele não aparece na tela eecho >&2
escreve a mensagem para o erro padrão.fonte
if hash foo &> /dev/null; then ...
?Eu nunca recebi as respostas anteriores para trabalhar na caixa a que tenho acesso. Por um lado,
type
foi instalado (fazendo o quemore
faz). Portanto, a diretiva integrada é necessária. Este comando funciona para mim:fonte
if
sintaxe, basta usarif builtin type -p vim; then ...
. E os backticks são realmente antigos e têm uma sintaxe obsoleta, e$()
são suportados mesmosh
em todos os sistemas modernos.Verifique várias dependências e informe o status aos usuários finais
Saída de amostra:
Ajuste o
10
para o comprimento máximo do comando. Não é automático, porque não vejo uma maneira POSIX não detalhada de fazê-lo: Como alinhar as colunas de uma tabela separada por espaço no Bash?Verifique se alguns
apt
pacotes estão instaladosdpkg -s
e, caso contrário, instale-os .Consulte: Verifique se um pacote apt-get está instalado e instale-o se não estiver no Linux
Foi mencionado anteriormente em: Como posso verificar se existe um programa a partir de um script Bash?
fonte
column -t
(parte do util-linux).Se você verificar a existência do programa, provavelmente o executará mais tarde. Por que não tentar executá-lo em primeiro lugar?
É uma verificação mais confiável que o programa é executado do que apenas olhar para diretórios PATH e permissões de arquivo.
Além disso, você pode obter algum resultado útil do seu programa, como a versão.
Obviamente, os inconvenientes são que alguns programas podem ser pesados para iniciar e outros não têm a
--version
opção de sair imediatamente (e com êxito).fonte
hash foo 2>/dev/null
: funciona com shell Z (Zsh), Bash, Dash e ash .type -p foo
: parece funcionar com o shell Z, Bash e ash ( BusyBox ), mas não o Dash (ele interpreta-p
como argumento).command -v foo
: funciona com shell Z, Bash, Dash, mas não ash (BusyBox) (-ash: command: not found
).Observe também que
builtin
não está disponível com ash e Dash.fonte
Use os Bash builtins se você puder:
...
fonte
which
não é um Bash embutido.-P
não é POSIX. Por que étype -P
preferido?O comando
-v
funciona bem se a opção POSIX_BUILTINS estiver configurada para o<command>
teste, mas poderá falhar se não. (Ele funcionou para mim por anos, mas recentemente encontrei um em que não funcionava.)Considero o seguinte mais à prova de falhas:
Uma vez que ele testa três coisas: permissão de caminho, existência e execução.
fonte
test -x $(which ls)
retorna 0, como o faztest -x $(which sudo)
, mesmo quels
esteja instalado e executável esudo
nem sequer é instalado dentro do recipiente estivador eu estou correndo.test -x "$(which <command>)"
ls
seja um alias? Eu não acho que funcionaria se o comando tem parâmetro.Para os interessados, nenhuma das metodologias das respostas anteriores funciona se você deseja detectar uma biblioteca instalada. Eu imagino que você fique com a verificação física do caminho (potencialmente para arquivos de cabeçalho e outros), ou algo assim (se você estiver em uma distribuição baseada no Debian):
Como você pode ver acima, uma resposta "0" da consulta significa que o pacote não está instalado. Esta é uma função do "grep" - um "0" significa que uma correspondência foi encontrada, um "1" significa que nenhuma correspondência foi encontrada.
fonte
cmd; if [ $? -eq 0 ]; then
deve ser reformulado paraif cmd; then
dpkg
ouapt
Há uma tonelada de opções aqui, mas fiquei surpreso por não ter falas rápidas. Isto é o que eu usei no início dos meus scripts:
Isso se baseia na resposta selecionada aqui e em outra fonte.
fonte
Eu diria que não existe uma maneira portátil e 100% confiável devido a oscilações
alias
es. Por exemplo:Obviamente, apenas o último é problemático (sem ofensa a Ringo!). Mas todos eles são válidos
alias
do ponto de vista decommand -v
.Para rejeitar outros pendentes
ringo
, precisamos analisar a saída doalias
comando interno do shell e recursá-los (command -v
não é superior aalias
aqui.) Não existe uma solução portátil para isso, e até mesmo um Bash- solução específica é bastante entediante.Observe que uma solução como essa rejeitará incondicionalmente
alias ls='ls -F'
:fonte
shopt -u expand_aliases
ignora / oculta esses apelidos e osshopt -s expand_aliases
mostra viacommand -v
.Isso informará de acordo com o local se o programa existe ou não:
fonte
O
which
comando pode ser útil. homem queRetorna 0 se o executável for encontrado e retorna 1 se não for encontrado ou não é executável:
O bom
which
é que ele descobre se o executável está disponível no ambiente em quewhich
é executado - ele economiza alguns problemas ...fonte
Minha configuração para um servidor Debian :
Eu tive o problema quando vários pacotes continham o mesmo nome.
Por exemplo
apache2
. Então esta foi a minha solução:fonte
Se vocês não conseguem obter as respostas aqui para o trabalho e estão arrancando os cabelos das costas, tente executar o mesmo comando usando
bash -c
. Basta olhar para esse delírio somnambular. Isto é o que realmente acontece quando você executa $ (subcomando):Primeiro. Pode fornecer uma saída completamente diferente.
Segundo. Pode não fornecer saída alguma.
fonte
.bashrc
tenho um[ -z "$PS1" ] && return
prefixo,# If not running interactively, don't do anything
então acho que essa é uma razão pela qual nem o fornecimento explícito de bashrc no modo não interativo não ajuda. O problema pode ser contornado chamando um script com um operador de ponto ss64.com/bash/source.html ,. ./script.sh
mas isso não é algo que você gostaria de lembrar de digitar toda vez.A variante hash tem uma armadilha: na linha de comando, você pode, por exemplo, digitar
ter processo executado. Para isso, a pasta pai da pasta one_folder deve estar em $ PATH . Mas quando você tenta fazer o hash deste comando, ele sempre será bem-sucedido:
fonte
$PATH
" - isso é completamente impreciso. Tente. Para que isso funcione, a pasta one_folder deve estar no diretório atual .Eu segundo o uso do "comando -v". Por exemplo:
fonte
Eu tive que verificar se o Git foi instalado como parte da implantação do servidor de IC . Meu script final do Bash foi o seguinte (servidor Ubuntu):
fonte
sudo
: sem o condicional, ele sempre parava e solicita a senha (a menos que você tenha feito um sudo recentemente). BTW, pode ser útil fazê-sudo -p "Type your password to install missing git-core: "
lo para que o prompt não saia do nada.Para imitar o Bash
type -P cmd
, podemos usar o compatível com POSIXenv -i type cmd 1>/dev/null 2>&1
.fonte
type
parece ser umbuiltin
na maioria das conchas de modo que este não pode trabalhar porqueenv
usosexecvp
para executarcommand
de modocommand
não pode ser umbuiltin
(eobuiltin
será sempre executado dentro do mesmo ambiente). Esta falha para mimbash
,ksh93
,zsh
,busybox [a]sh
edash
todos os quais fornecemtype
como um builtin shell.Se não houver nenhum
type
comando externo disponível (como concedido aqui ), podemos usar o POSIX compatívelenv -i sh -c 'type cmd 1>/dev/null 2>&1'
:Pelo menos no Mac OS X 10.6.8 (Snow Leopard) usando o Bash 4.2.24 (2)
command -v ls
não corresponde a um movimento/bin/ls-temp
.fonte
Caso você queira verificar se um programa existe e é realmente um programa, não um comando interno do Bash , então
command
,type
ehash
não são adequados para testar como eles todo o retorno 0 status de saída para built-in comandos.Por exemplo, existe o programa de horário que oferece mais recursos do que o comando interno de horário . Para verificar se o programa existe, sugiro usar
which
como no exemplo a seguir:fonte
Eu queria que a mesma pergunta fosse respondida, mas executada em um Makefile.
fonte
Roteiro
Resultado
fonte
Eu uso isso, porque é muito fácil:
ou
Ele usa o status de eco dos programas incorporados e do shell na saída padrão e nada no erro padrão. Por outro lado, se um comando não for encontrado, ele faz eco do status apenas para erro padrão.
fonte