Estou lendo exemplos do bash, if
mas 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?
bash
if-statement
rkmax
fonte
fonte
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-o
e 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.fonte
[[ ]]
(por exemplo, bash com#!/bin/bash
ou#!/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 queX
seja 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
a
oub
(como+
ouindex
) e faz comparação numérica sea
e seb
parecem com números inteiros decimais.expr "x$a" '<' "x$b"
trabalha em torno de ambos.³ e também falha em alguns valores de
a
oub
como!
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.fonte
[]
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:
se $ var estiver nulo / vazio, é isso que o script vê:
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.fonte
[[
é 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
[[
.fonte
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)
fonte
O manual do Bash diz:
(O comando test é idêntico a [])
fonte