Vejo que posso fazer
$ [ -w /home/durrantm ] && echo "writable"
writable
ou
$ test -w /home/durrantm && echo "writable"
writable
ou
$ [[ -w /home/durrantm ]] && echo "writable"
writable
Eu gosto de usar a terceira sintaxe. Eles são equivalentes em todos os aspectos e em todos os casos negativos e de ponta? Existem diferenças de portabilidade, por exemplo, entre o bash no Ubuntu e no OS X ou versões mais antigas / mais recentes do bash, por exemplo, antes / depois do 4.0 e ambos expandem as expressões da mesma maneira?
shell
posix
test
portability
Michael Durrant
fonte
fonte
[ … ]
vs[[ … ]]
vstest …
, há respostas mais completas nesta pergunta quase duplicada .Respostas:
[
é sinônimo dotest
comando e é simultaneamente um comando interno e separado do bash . Mas[[
é uma palavra - chave bash e funciona apenas em algumas versões. Portanto, por motivos de portabilidade, é melhor usar um[]
ou maistest
fonte
[
o POSIX é incorporado ou o Bash?test
e[
similares. Se um shell pode fazer a avaliação por si próprio, isso economiza um processo e o torna um pouco mais rápido, mas o resultado deve ser o mesmo.[
é definido pela POSIX e, portanto, maximamente portátil (que parece ser o ponto inteiro desta questão, se não me engano)[
etest
são POSIX . Parece não haver nenhum "recomendado", embora a única diferença (?) Que eu possa identificar entre eles é quetest
"não reconheça o argumento" - "[como um delimitador indicando o fim das opções]" (? - implicando que " - " é reconhecido como o fim dos argumentos[
, pelo qual não posso apresentar um bom caso de teste de qualquer maneira. Mas discordo. Use o que você quiser. OMI[
parece elegante, mas étest
claramente um comando)Sim, existem diferenças. Os mais portáteis são
test
ou[ ]
. Ambos fazem parte da especificação POSIXtest
.A
if ... fi
construção também é definida pelo POSIX e deve ser completamente portátil.O
[[ ]]
é umksh
recurso que também está presente em algumas versões dobash
( todos os modernos ), emzsh
e talvez em outros, mas não está presente emsh
oudash
ou dos outros conchas mais simples.Então, para fazer seus scripts portátil, usar
[ ]
,test
ouif ... fi
.fonte
bash
ezsh
há suporte[[
há muito tempo (obash
adicionamos no final dos anos 90, ozsh
mais tardar em 2000, e eu ficaria surpreso se algum dia tivesse falta de suporte), então é improvável que você encontre uma versão deles[[
. Encontrar um shell diferente compatível com POSIX (comodash
) é muito mais provável.[[
é que as expansões de parâmetros não precisam ser citadas: o[[-f $file]]
evento funciona se$file
contiver caracteres de espaço em branco.[[ $a =~ ^reg.*exp.*$' ]]
Observe que isso
[] && cmd
não é o mesmo queif .. fi
construção.Às vezes, seu comportamento é bastante semelhante e você pode usar em
[] && cmd
vez deif .. fi
. Mas apenas algumas vezes. Se você tiver mais de um comando para executar se condição ou precisar deif .. else .. fi
cuidado e qual a lógica.Alguns exemplos:
Não é o mesmo que
porque se
ls
falhar,echo
será executado o que não acontecerá comif
.Outro exemplo:
não é o mesmo que
embora essa construção atue da mesma maneira
observe que o
;
eco é importante e deve estar lá.Então, retomando a declaração acima, podemos dizer
[] && cmd
== se o primeiro comando for bem sucedido, execute o próximoif .. fi
== se condição (que também pode ser o comando de teste), execute o (s) comando (s)Portanto, apenas para portabilidade
[
e[[
uso[
.if
é compatível com POSIX. Então, se você tiver que escolher entre[
eif
escolher a olhar para a sua tarefa e comportamento esperado.fonte
[ -z "$VAR" ] && { ls file; true; } || echo wiiii
. É um pouco mais detalhado, mas ainda é mais curto que aif...fi
construção.[
eif
como legendas, mas não são. Na verdade, é o&&
que está substituindo oif
.[
executa algum código e retorna um status, muito parecidols
egrep
faria.if
ramifica a execução dependendo do status de retorno do comando (instrução) fornecido após o if, poderia ser qualquer comando (instrução).&&
executa a próxima instrução somente se a anterior retornou 0, como uma simplesif..then..fi
.Na verdade,
&&
é isso que está substituindo oif
, não otest
: umaif
instrução nos scripts de shell testa se um comando retornou um status de saída "bem-sucedido" (zero); no seu exemplo, o comando é[
.Portanto, existem duas coisas que você varia aqui: o comando usado para executar o teste e a sintaxe usada para executar o código com base no resultado desse teste.
Comandos de teste:
test
é um comando padronizado para avaliar propriedades de strings e arquivos; no seu exemplo, você está executando o comandotest -w /home/durrantm
[
é um pseudônimo desse comando, igualmente padronizado, que possui um último argumento obrigatório]
para parecer uma expressão entre colchetes; não se deixe enganar, ainda é apenas um comando (você pode até achar que seu sistema possui um arquivo chamado/bin/[
)[[
é uma versão estendida do comando test incorporada em alguns shells, mas não faz parte do mesmo padrão POSIX; inclui opções extras que você não está usando aquiExpressões condicionais:
&&
operador ( padronizado aqui ) executa uma operação AND lógica, avaliando dois comandos e retornando 0 (que representa true) se ambos retornarem 0; ele avaliará apenas o segundo comando se o primeiro retornar zero, para que possa ser usado como uma condição condicional simplesif ... then ... fi
construto ( padronizado aqui ) usa o mesmo método para julgar a "verdade", mas permite uma lista composta de instruções nathen
cláusula, em vez do comando único fornecido por um&&
curto-circuito, além de fornecerelif
eelse
cláusulas difíceis de escrever usando apenas&&
e||
. Observe que não há colchetes ao redor da condição em umaif
instrução .Portanto, todos os itens a seguir são igualmente portáteis e totalmente equivalentes para o seu exemplo:
test -w /home/durrantm && echo "writable"
[ -w /home/durrantm ] && echo "writable"
if test -w /home/durrantm; then echo "writable"; fi
if [ -w /home/durrantm ]; then echo "writable"; fi
Embora o seguinte também seja equivalente, mas menos portátil devido à natureza não padrão de
[[
:[[ -w /home/durrantm ]] && echo "writable"
if [[ -w /home/durrantm ]]; then echo "writable"; fi
fonte
Para portabilidade, use
test
/[
. Mas se você não precisar da portabilidade, para a sanidade de si mesmo e de outras pessoas que estão lendo seu script, use[[
. :)Veja também
What is the difference between test, [ and [[ ?
no BashFAQ .fonte
Se você deseja portabilidade fora do mundo Bourne, então:
é o mais portátil. Trabalha nas conchas dos Bourne
csh
e nasrc
famílias.saída seria
"writable"
em vez dewritable
em conchas darc
família (rc
,es
,akanga
, onde"
não é especial).não funcionaria em shells da família
csh
ourc
em sistemas que não possuem um[
comando$PATH
(alguns são conhecidos por possuir,test
mas não o[
apelido).só funciona em conchas da família Bourne.
só funciona em
ksh
(de onde se originou)zsh
ebash
(todos os 3 da família Bourne).Nenhum funcionaria no
fish
shell onde você precisa:ou:
fonte
Minha razão mais importante para escolher
if foo; then bar; fi
oufoo && bar
é se o status de saída de todo o comando é importante.comparar:
com:
Você pode pensar que eles fazem o mesmo; no entanto, se
foo
falhar (ou for falso, dependendo do seu ponto de vista), no primeiro exemplo o do_baz não será executado, pois o script será encerrado ... Oset -e
comando instrui o shell a sair imediatamente se algum comando retornar um status falso. Muito útil se você estiver fazendo coisas como:Você não deseja que o script continue em execução se
cd
falhar por qualquer motivo.fonte
foo
não abortará o script nos dois casos. Isso é um caso especial paraset -e
(quando o comando é avaliado como uma condição (para a esquerda, de algum && / || ou se / quando / até / ELSIF ... condições) A falhando.bar
Sairia do shell em ambos os casos.cd /some/directory && rm -rf -- *
oucd /some/directory || exit; rm -rf -- *
(ainda não remove arquivos ocultos). Pessoalmente, não gosto da ideia de usarset -e
como desculpa para não fazer esforço para escrever o código correto.