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?
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?
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.
[[ ]]
(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 que X
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
ou b
(como +
ou index
) e faz comparação numérica se a
e se b
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
ou b
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.
[]
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 [])