Estou lendo exemplos do bash, ifmas alguns exemplos são escritos com colchetes simples:
if [ -f $param ]
then
#...
fi
outros com colchetes duplos:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
Qual é a diferença?
Estou lendo exemplos do bash, ifmas alguns exemplos são escritos com colchetes simples:
if [ -f $param ]
then
#...
fi
outros com colchetes duplos:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
Qual é a diferença?
Respostas:
Simples []são os testes de condições compatíveis com o posix shell.
Double [[]]é uma extensão do padrão []e é suportado pelo bash e outros shells (por exemplo, zsh, ksh). Eles suportam operações extras (bem como as operações posix padrão). Por exemplo: em ||vez de -oe regex combinando com =~. Uma lista completa de diferenças pode ser encontrada na seção manual do bash sobre construções condicionais .
Use []sempre que quiser que seu script seja portável através de shells. Use [[]]se você quiser expressões condicionais não suportadas []e não precisar ser portátil.
[[ ]](por exemplo, bash com #!/bin/bashou #!/usr/bin/env bash), você deve usar a opção portable. Os scripts que assumem que o / bin / sh suporta extensões como essa serão interrompidos em sistemas operacionais como os lançamentos recentes do Debian e Ubuntu, onde esse não é o caso.
Diferenças de comportamento
Testado no Bash 4.3.11:
Extensão POSIX vs Bash:
[ é POSIX[[é uma extensão do Bash¹ documentada em: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructscomando regular vs magia
[ é apenas um comando regular com um nome estranho.
]é apenas um argumento [que impede que outros argumentos sejam usados.
O Ubuntu 16.04, na verdade, tem um executável /usr/bin/[fornecido pelo coreutils, mas a versão interna do bash tem precedência.
Nada é alterado na maneira como Bash analisa o comando.
Em particular, <é o redirecionamento &&e ||concatena vários comandos, ( )gera sub-conchas, a menos que seja escapado \, e a expansão de palavras acontece normalmente.
[[ X ]]é uma construção única que faz com que Xseja analisado magicamente. <, &&, ||E() são tratados de maneira especial, e regras de decomposição palavra são diferentes.
Existem também outras diferenças como =e =~.
No Bashese: [é um comando interno e [[é uma palavra-chave: /ubuntu/445749/whats-the-difference-between-shell-builtin-and-shell-keyword
<
[[ a < b ]]: comparação lexicográfica[ a \< b ]: O mesmo que acima. \necessário ou o redirecionamento é semelhante a qualquer outro comando. Extensão Bash.expr a \< b > /dev/null: Equivalente ao POSIX², consulte: Como testar seqüências lexicográficas menores ou iguais no Bash?&& e ||
[[ a = a && b = b ]]: verdadeiro, lógico e[ a = a && b = b ]: erro de sintaxe, &&analisado como um separador de comandos ANDcmd1 && cmd2 [ a = a -a b = b ]: equivalente, mas reprovado pelo POSIX³[ a = a ] && [ b = b ]: POSIX e equivalente confiável(
[[ (a = a || a = b) && a = b ]]: false[ ( a = a ) ]: erro de sintaxe, ()é interpretado como um subshell[ \( a = a -o a = b \) -a a = b ]: equivalente, mas ()foi descontinuado pelo POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]POSIX equivalente 5divisão de palavras e geração de nome de arquivo após expansões (divisão + glob)
x='a b'; [[ $x = 'a b' ]]: true, aspas não necessáriasx='a b'; [ $x = 'a b' ]: erro de sintaxe, expande para [ a b = 'a b' ]x='*'; [ $x = 'a b' ]: erro de sintaxe se houver mais de um arquivo no diretório atual.x='a b'; [ "$x" = 'a b' ]: Equivalente POSIX=
[[ ab = a? ]]: true, porque faz a correspondência de padrões ( * ? [são mágicos). Não é expandido para arquivos no diretório atual.[ ab = a? ]: a?glob se expande. Portanto, pode ser verdadeiro ou falso, dependendo dos arquivos no diretório atual.[ ab = a\? ]: expansão falsa, não global=e ==são iguais em ambos [e [[, mas ==é uma extensão do Bash.case ab in (a?) echo match; esac: Equivalente POSIX[[ ab =~ 'ab?' ]]: falso 4 , perde mágica com''[[ ab? =~ 'ab?' ]]: verdade=~
[[ ab =~ ab? ]]: true, correspondência de expressão regular estendida POSIX , ?não expande glob[ a =~ a ]: erro de sintaxe. Nenhum equivalente do bash.printf 'ab\n' | grep -Eq 'ab?': Equivalente ao POSIX (apenas dados de linha única)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': Equivalente POSIX.Recomendação : use sempre [].
Existem equivalentes POSIX para cada [[ ]]construção que eu já vi.
Se você usa [[ ]]você:
[é apenas um comando regular com um nome estranho, sem semântica especial envolvida.¹ Inspirado na [[...]]construção equivalente no shell Korn
² mas falha para alguns valores de aou b(como +ou index) e faz comparação numérica se ae se bparecem com números inteiros decimais. expr "x$a" '<' "x$b"trabalha em torno de ambos.
³ e também falha em alguns valores de aou bcomo !ou (.
4 no bash 3.2 e superior e a compatibilidade fornecida com o bash 3.1 não está ativada (como em BASH_COMPAT=3.1)
5 embora o agrupamento (aqui com o {...;}grupo de comandos em vez do (...)qual executaria um subshell desnecessário) não seja necessário, pois os operadores ||e &&shell (em oposição aos operadores ||e && [[...]]ou -o/ -a [operadores) têm igual precedência. Então [ a = a ] || [ a = b ] && [ a = b ]seria equivalente.
[] deve ser lida como Minha preferência : use []se você não quiser perder a portabilidade . Conforme declarado aqui : Se a portabilidade / conformidade com o POSIX ou o BourneShell for uma preocupação, a sintaxe antiga deve ser usada. Se, por outro lado, o script exigir BASH, Zsh ou KornShell, a nova sintaxe geralmente será mais flexível, mas não necessariamente compatível com versões anteriores. Eu prefiro ir com [[ ab =~ ab? ]]se eu puder e não têm preocupação com compatibilidade com versões anteriores do queprintf 'ab' | grep -Eq 'ab?'
Entre parênteses simples para teste de condição (por exemplo, [...]), alguns operadores, como single, =são suportados por todas as conchas, enquanto o uso do operador ==não é suportado por algumas conchas mais antigas.
Dentro de colchetes duplos para teste de condição (ou seja, [...]), não há diferença entre usar =ou ==em cascas velhas ou novas.
Editar: Devo também observar que: No bash, sempre use colchetes [...] duplos, se possível, porque é mais seguro que colchetes simples. Ilustrarei o porquê com o seguinte exemplo:
if [ $var == "hello" ]; then
se $ var estiver nulo / vazio, é isso que o script vê:
if [ == "hello" ]; then
o que quebrará seu script. A solução é usar colchetes duplos ou sempre lembrar de colocar aspas em torno de suas variáveis ( "$var"). Parênteses duplos são melhores práticas de codificação defensiva.
[[ é uma palavra-chave bash semelhante (mas mais poderosa que) a [ comando.
Vejo
http://mywiki.wooledge.org/BashFAQ/031 e http://mywiki.wooledge.org/BashGuide/TestsAndConditionals
A menos que você esteja escrevendo para o POSIX sh, recomendamos [[.
você pode usar colchetes duplos para correspondência de expressões regulares leves, por exemplo:
if [[ $1 =~ "foo.*bar" ]] ; then
(desde que a versão do bash que você está usando suporte esta sintaxe)
O manual do Bash diz:
Quando usados com [[, os operadores '<' e '>') classificam lexicograficamente usando o código do idioma atual. O comando test usa pedidos ASCII.
(O comando test é idêntico a [])