Respostas:
A diferença entre [[ … ]]
e [ … ]
é abordada principalmente no uso de suporte simples ou duplo - bash . Crucialmente, [[ … ]]
é uma sintaxe especial, enquanto que [
é um nome engraçado para um comando. [[ … ]]
tem regras especiais de sintaxe para o que está dentro, [ … ]
não.
Com as rugas adicionadas de um curinga, veja como [[ $a == z* ]]
é avaliado:
[[ … ]]
construção condicional em torno da expressão condicional $a == z*
.==
operador binário, com os operandos $a
e z*
.a
.==
operador: teste se o valor da variável a
corresponde ao padrão z*
.Veja como [ $a == z* ]
é avaliado:
[
comando com os argumentos formados por avaliar as palavras $a
, ==
, z*
, ]
.$a
para o valor da variável a
.a
é a seqüência de 6 caracteres foo b*
(obtido por exemplo a='foo b*'
) e a lista de arquivos no diretório atual é ( bar
, baz
, qux
, zim
, zum
), então o resultado da expansão é a lista de palavras seguintes: [
, foo
, bar
, baz
, ==
, zim
, zum
, ]
.[
com os parâmetros obtidos na etapa anterior.
[
comando reclama de um erro de sintaxe e retorna o status 2.Nota: Na [[ $a == z* ]]
etapa 3, o valor de a
não sofre divisão de palavras e geração de nome de arquivo, porque está em um contexto em que uma única palavra é esperada (o argumento à esquerda do operador condicional ==
). Na maioria dos casos, se uma única palavra faz sentido nessa posição, a expansão variável se comporta como entre aspas duplas. No entanto, há uma exceção a essa regra: in [[ abc == $a ]]
, se o valor de a
contiver curingas, a
será comparado com o padrão de curinga. Por exemplo, se o valor de a
for, a*
então [[ abc == $a ]]
é verdadeiro (porque o curinga *
proveniente da expansão não citada de $a
correspondências *
) enquanto que [[ abc == "$a" ]]
é falso (porque o caractere comum*
provenientes da expansão citada de $a
não corresponde bc
). Dentro [[ … ]]
, aspas duplas não fazer a diferença, exceto no lado direito dos operadores cadeia correspondente ( =
, ==
, !=
e =~
).
[
é um alias para o test
comando. A versão 6 do Unix possuía um if
comando, mas a versão 7 (1979) veio com o novo shell Bourne que possuía algumas construções de programação, incluindo a construção if-then-else-elif-fi, e a versão 7 do Unix adicionou um test
comando que executava a maior parte do "testes" que foram executados pelo if
comando em versões mais antigas.
[
foi feito um alias para test
e ambos foram criados no shell no Unix System III (1981) . Embora se deva observar que algumas variantes do Unix não possuíam um [
comando até muito mais tarde ( até o início dos anos 2000 em alguns BSDs sh
baseados no shell Almquist (um test
built-in sempre foi incluído no ash
código-fonte, mas naqueles BSDs foi inicialmente desativado)).
Observe que test
aka [
é um comando para fazer "testes"; não há atribuição que esse comando faça; portanto, não há razão para desambiguar entre um operador de atribuição e igualdade, portanto, o operador de igualdade é =
. ==
é suportado apenas por algumas implementações recentes de [
(e é apenas um alias para =
).
Como [
nada mais é que um comando, ele é analisado da mesma maneira que qualquer outro comando do shell.
Especificamente, no seu exemplo, $a
porque não é citado, seria dividido em várias palavras de acordo com as regras usuais de divisão de palavras, e cada palavra passaria pela geração do nome do arquivo, também conhecida como globbing, para resultar em possivelmente mais palavras, cada uma dessas palavras resultando em um argumento separado para o [
comando.
Da mesma forma, z*
seria expandido para a lista de nomes de arquivos no diretório atual começando com z
.
Assim, por exemplo, se $a
é b* = x
, e há z1
, z2
, b1
e b2
arquivos no diretório atual, o [
comando teria 9 argumentos: [
, b1
, b2
, =
, x
, ==
, z1
, z2
e ]
.
[
analisa seus argumentos como uma expressão condicional. Esses 9 argumentos não somam uma expressão condicional válida, portanto, provavelmente retornaria um erro.
A [[ ... ]]
construção foi introduzida pelo shell Korn provavelmente por volta de 1988, pois ksh86a
em 1987 não o ksh88
possuía desde o início.
Além do ksh (todas as implementações), [[...]]
também é suportado pelo bash (desde a versão 2.02) e pelo zsh, mas as três implementações são diferentes e há diferenças entre cada versão de um mesmo shell, embora as alterações sejam geralmente compatíveis com versões anteriores (uma exceção notável é o bash =~
operador conhecido por quebrar alguns scripts após uma determinada versão quando seu comportamento foi alterado). [[...]]
não é especificado pelo POSIX, ou Unix ou Linux (LSB). Ele foi considerado para inclusão algumas vezes, mas não foi incluído, pois a funcionalidade comum suportada pelos shells principais já está coberta pelo [
comando e pela case-in-esac
construção.
Toda a [[ ... ]]
construção compõe um comando. Ou seja, ele tem um status de saída (que é seu ativo mais importante, pois é o resultado da avaliação da expressão condicional), você pode canalizá-lo para outro comando (embora não seja útil) e geralmente usá-lo onde quiser use qualquer outro comando (somente dentro do shell, pois é uma construção de shell), mas não é analisado como um comando simples normal. O que está dentro é analisado pelo shell como uma expressão condicional e as regras usuais de divisão de palavras e geração de nome de arquivo se aplicam de maneira diferente.
[[ ... ]]
conhece ==
desde o início e é equivalente a =
1 . Um erro do ksh (e está causando confusão e muitos bugs) é que o operador =
e ==
não é um operador de igualdade, mas um operador de correspondência de padrões (embora o aspecto de correspondência possa ser desativado com aspas, mas com regras pouco claras que diferem de shell para shell).
No código acima [[ $a == z* ]]
, o shell analisaria isso em vários tokens em regras semelhantes às usuais, reconhecendo-o como uma comparação de correspondência de padrões, tratado z*
como um padrão para corresponder ao conteúdo da a
variável.
Geralmente, é mais difícil dar um tiro no pé [[ ... ]]
do que com o [
comando. Mas algumas regras como
-a
or -o
(use vários [
comandos e os operadores &&
e ||
shell )Torne [
confiável com os shells POSIX.
[[...]]
em diferentes shells suportam operadores extras, como operadores de -nt
correspondência regexp ... mas a lista e o comportamento variam de shell para shell e de versão para versão.
Portanto, a menos que você saiba com qual shell e versão mínima seu script será interpretado, provavelmente é mais seguro manter o [
comando padrão .
1 Uma exceção: [[...]]
foi adicionada ao bash na versão 2.02
. Até 2.03
onde foi alterado, [[ x = '?' ]]
retornaria true enquanto [[ x == '?' ]]
retornaria false. A citação não impediu a correspondência de padrões ao usar o =
operador nessas versões, mas impediu ao usar ==
.
[ '!' = foo -o a = a ]
em bash
por exemplo.
ambos são usados para avaliar expressões e [[não funcionará com o shell de registro mais antigo POSIX e [[também suportam correspondência de padrões e regex. exemplo tente estes
[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"
[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"
[[...]]
suporta regexps apenas em algumas versões de alguns shells, assim como algumas versões de [
suportam a correspondência de regexp. Para efeito de comparação arithemtic, naqueles conchas que o apoio [[
, você prefere escrever(( n == 0 && y == 0))