Como [[está embutido no shell e não possui requisitos herdados, você não precisa se preocupar com a divisão de palavras com base na variável IFS para atrapalhar as variáveis ​​que avaliam uma string com espaços. Portanto, você realmente não precisa colocar a variável entre aspas duplas.
Você não precisa se preocupar em citar o lado esquerdo do teste para que ele seja lido como uma variável.
Você não precisa escapar menor que e maior que < >com barras invertidas para que eles não sejam avaliados como redirecionamento de entrada, o que pode realmente atrapalhar algumas coisas substituindo arquivos. Isso novamente volta a [[ser um builtin. Se [ (teste) for um programa externo, o shell teria que fazer uma exceção na maneira como avalia <e >apenas se /bin/testestiver sendo chamado, o que não faria muito sentido.
$ [ a < b ]
-bash: b: No such file or directory
$ [[ a < b ]]
O primeiro exemplo retorna um erro porque o bash tenta redirecionar o arquivo b para o comando [ a ]. O segundo exemplo realmente faz o que você espera. O caractere < não tem mais seu significado especial de operador de Redirecionamento de Arquivo.
[ \( a = a -o a = b \) -a a = b ]: equivalente, mas (), -a, e -osão obsoletos pelo POSIX. Sem \( \)seria verdade porque -atem maior precedência do que-o
{ [ a = a ] || [ a = b ]; } && [ a = b ]equivalente POSIX não obsoleto. Neste caso em particular, no entanto, poderÃamos ter escrito apenas: [ a = a ] || [ a = b ] && [ a = b ]porque os operadores ||e shell têm precedência igual ao contrário de e e , e&&[[ || ]][[ && ]]-o-a[
divisão de palavras e geração de nome de arquivo em expansões (split+glob)
x='a b'; [[ $x = 'a b' ]]: true, as aspas não são necessárias
x='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 correspondência de padrões ( * ? [são mágicos). Não expande glob para arquivos no diretório atual.
[ ab = a? ]: a?globo se expande. Portanto, pode ser verdadeiro ou falso dependendo dos arquivos no diretório atual.
case ab in (a?) echo match; esac: equivalente POSIX
[[ ab =~ 'ab?' ]]: false, perde a magia ''no Bash 3.2 e superior e a compatibilidade fornecida para o bash 3.1 não está ativada (como com BASH_COMPAT=3.1)
Existem várias diferenças. Na minha opinião, alguns dos mais importantes são:
[
é um embutido no Bash e em muitos outros shells modernos. O builtin[
é semelhante aotest
requisito adicional de um fechamento]
. Os builtins[
etest
imitam a funcionalidade/bin/[
e/bin/test
junto com suas limitações para que os scripts sejam compatÃveis com versões anteriores. Os executáveis ​​originais ainda existem principalmente para conformidade com POSIX e compatibilidade com versões anteriores. A execução do comandotype [
no Bash indica que[
é interpretado como interno por padrão. (Nota:which [
apenas procura executáveis ​​no PATH e é equivalente atype -P [
. Você pode executartype --help
para obter detalhes)[[
não é tão compatÃvel, não funcionará necessariamente com o que quer que seja/bin/sh
. Assim[[
é a opção mais moderna Bash / Zsh / Ksh.[[
está embutido no shell e não possui requisitos herdados, você não precisa se preocupar com a divisão de palavras com base na variável IFS para atrapalhar as variáveis ​​que avaliam uma string com espaços. Portanto, você realmente não precisa colocar a variável entre aspas duplas.Na maior parte, o resto é apenas uma sintaxe melhor. Para ver mais diferenças, recomendo este link para uma resposta de perguntas frequentes: Qual é a diferença entre teste, [ e [[ ? . Na verdade, se você leva a sério os scripts bash, recomendo a leitura de todo o wiki , incluindo o FAQ, Pitfalls e Guide. A seção de teste da seção de guia também explica essas diferenças e por que o(s) autor(es) acham que
[[
é uma escolha melhor se você não precisa se preocupar em ser tão portátil. Os principais motivos são:< >
com barras invertidas para que eles não sejam avaliados como redirecionamento de entrada, o que pode realmente atrapalhar algumas coisas substituindo arquivos. Isso novamente volta a[[
ser um builtin. Se [ (teste) for um programa externo, o shell teria que fazer uma exceção na maneira como avalia<
e>
apenas se/bin/test
estiver sendo chamado, o que não faria muito sentido.Resumidamente:
Palavras-chave: as palavras- chave são como builtins, mas a principal diferença é que regras especiais de análise se aplicam a elas. Por exemplo, [ é um bash embutido, enquanto [[ é uma palavra-chave do bash. Ambos são usados ​​para testar coisas, mas como [[ é uma palavra-chave em vez de um built-in, ele se beneficia de algumas regras especiais de análise que tornam muito mais fácil:
O primeiro exemplo retorna um erro porque o bash tenta redirecionar o arquivo b para o comando [ a ]. O segundo exemplo realmente faz o que você espera. O caractere < não tem mais seu significado especial de operador de Redirecionamento de Arquivo.
Fonte: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments
Diferenças de comportamento
Algumas diferenças no Bash 4.3.11:
Extensão POSIX vs Bash:
[
é POSIX[[
é uma extensão Bash inspirada no shell Korncomando regular vs magia
[
é apenas um comando regular com um nome estranho.]
é apenas o último argumento de[
.O Ubuntu 16.04 na verdade tem um executável para ele
/usr/bin/[
fornecido por coreutils , mas a versão interna do bash tem precedência.Nada é alterado na maneira como o Bash analisa o comando.
Em particular,
<
é o redirecionamento&&
e||
concatena vários comandos,( )
gera subshells, a menos que seja escapado por\
, e a expansão de palavras acontece como de costume.[[ X ]]
é uma construção única que fazX
ser analisada magicamente.<
,&&
,||
e()
são tratados especialmente, e as regras de divisão de palavras são diferentes.Há também outras diferenças como
=
e=~
.Em Bashese:
[
é um comando interno e[[
é uma palavra-chave: https://askubuntu.com/questions/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 então redireciona como para qualquer outro comando. Extensão Bash.expr x"$x" \< x"$y" > /dev/null
ou[ "$(expr x"$x" \< x"$y")" = 1 ]
: equivalentes POSIX, consulte: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989&&
e||
[[ a = a && b = b ]]
: verdadeiro, lógico e[ a = a && b = b ]
: erro de sintaxe,&&
analisado como um separador de comando ANDcmd1 && cmd2
[ a = a ] && [ b = b ]
: POSIX equivalente confiável[ a = a -a b = b ]
: quase equivalente, mas obsoleto pelo POSIX porque é insano e falha para alguns valores dea
oub
semelhantes!
ou(
que seriam interpretados como operações lógicas(
[[ (a = a || a = b) && a = b ]]
: falso. Sem( )
, seria verdadeiro porque[[ && ]]
tem maior precedência do que[[ || ]]
[ ( a = a ) ]
: erro de sintaxe,()
é interpretado como um subshell[ \( a = a -o a = b \) -a a = b ]
: equivalente, mas()
,-a
, e-o
são obsoletos pelo POSIX. Sem\( \)
seria verdade porque-a
tem maior precedência do que-o
{ [ a = a ] || [ a = b ]; } && [ a = b ]
equivalente POSIX não obsoleto. Neste caso em particular, no entanto, poderÃamos ter escrito apenas:[ a = a ] || [ a = b ] && [ a = b ]
porque os operadores||
e shell têm precedência igual ao contrário de e e , e&&
[[ || ]]
[[ && ]]
-o
-a
[
divisão de palavras e geração de nome de arquivo em expansões (split+glob)
x='a b'; [[ $x = 'a b' ]]
: true, as aspas não sã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 correspondência de padrões (* ? [
são mágicos). Não expande glob para arquivos no diretório atual.[ ab = a? ]
:a?
globo se expande. Portanto, pode ser verdadeiro ou falso dependendo dos arquivos no diretório atual.[ ab = a\? ]
: false, não expansão glob=
e==
são os mesmos em ambos[
e[[
, mas==
é uma extensão Bash.case ab in (a?) echo match; esac
: equivalente POSIX[[ ab =~ 'ab?' ]]
: false, perde a magia''
no Bash 3.2 e superior e a compatibilidade fornecida para o bash 3.1 não está ativada (como comBASH_COMPAT=3.1
)[[ ab? =~ 'ab?' ]]
: verdadeiro=~
[[ ab =~ ab? ]]
: true, correspondência de expressão regular estendida?
POSIX, não expande glob[ a =~ a ]
: erro de sintaxe. Nenhum equivalente de bash.printf 'ab\n' | grep -Eq 'ab?'
: equivalente POSIX (somente 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 vi.Se você usa
[[ ]]
você:[
é apenas um comando regular com um nome estranho, nenhuma semântica especial está envolvida.Agradecimentos a Stéphane Chazelas por importantes correções e acréscimos.
Single Bracket , ou seja,
[]
é compatÃvel com shell POSIX para incluir uma expressão condicional.Double Brackets , ou seja,
[[]]
é uma versão aprimorada (ou extensão) da versão POSIX padrão, isso é suportado pelo bash e outros shells (zsh, ksh).No bash, para comparação numérica, usamos
eq
, ene
, com colchetes duplos para comparação, podemos usar , e literalmente .lt
gt
==
!=
<,
>
[
é um sinônimo para comando de teste. Mesmo que esteja embutido no shell, ele cria um novo processo.[[
é uma nova versão melhorada dele, que é uma palavra-chave, não um programa.por exemplo:
Com base em uma leitura rápida das seções relevantes da página de manual, a principal diferença parece ser que os operadores
==
and!=
correspondem a um padrão, em vez de uma string literal, e também que existe o=~
operador de comparação regex.