Eu só queria saber qual é exatamente a diferença entre
[[ $STRING != foo ]]
e
[ $STRING != foo ]
Além disso, o último é compatível com posix, encontrado em sh e o primeiro é uma extensão encontrada no bash.
Eu só queria saber qual é exatamente a diferença entre
[[ $STRING != foo ]]
e
[ $STRING != foo ]
Além disso, o último é compatível com posix, encontrado em sh e o primeiro é uma extensão encontrada no bash.
Respostas:
Existem várias diferenças. Na minha opinião, alguns dos mais importantes são:
[é um builtin no Bash e em muitas outras conchas modernas. O builtin [é semelhante ao testrequisito adicional de um fechamento ]. Os componentes internos [e testimitam a funcionalidade /bin/[e /bin/testsuas 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 comando type [no Bash indica que [é interpretado como um interno por padrão. (Nota: which [procura apenas executáveis no PATH e é equivalente a type -p [)[[não é tão compatível, não funcionará necessariamente com o que quer que /bin/shaponte. Assim [[é a opção Bash / Zsh / Ksh mais moderna.[[está embutido no shell e não possui requisitos herdados, não é necessário se preocupar com a divisão de palavras com base na variável IFS para atrapalhar as variáveis avaliadas para uma sequência 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 da FAQ: Qual é a diferença entre test, [e [[? . De fato, se você é sério sobre o bash scripting, recomendo a leitura de todo o wiki , incluindo as Perguntas frequentes, Armadilhas e Guia. A seção de teste da seção do guia também explica essas diferenças e por que o (s) autor (es) pensam 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 não sejam avaliadas como redirecionamento de entrada, o que pode realmente atrapalhar algumas coisas substituindo arquivos. Isso novamente volta a [[ser um builtin. Se [(test) for um programa externo, o shell precisaria abrir uma exceção na maneira como avalia <e >apenas se /bin/testestiver sendo chamado, o que não faria sentido.Em resumo:
[é uma festa embutida
[[]] são bash Palavras-chave
Palavras-chave: as palavras- chave são muito parecidas com os built-in, mas a principal diferença é que regras especiais de análise se aplicam a elas. Por exemplo, [é um bash integrado, enquanto [[é uma palavra-chave do bash. Ambos são usados para testar coisas, mas como [[é uma palavra-chave e não um builtin, ela se beneficia de algumas regras de análise especiais que facilitam muito:
$ [ 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, na verdade, faz o que você espera. O caractere <não tem mais seu significado especial de operador Redirecionamento de arquivo.
Fonte: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments
[é um comando shell POSIX; ele não precisa ser incorporado. ]é apenas um argumento que esse comando procura, para que a sintaxe seja equilibrada. O comando é um sinônimo, testexceto que testnão procura um fechamento ].
Diferenças de comportamento
Algumas diferenças 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, possui 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: 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 o redirecionamento é semelhante a qualquer outro comando. Extensão Bash.expr a \< b > /dev/null: Equivalente ao POSIX², consulte: https://stackoverflow.com/questions/21294867/how-to-test-strings-for Castellicographic-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 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?' ]]: verdadeiro=~
[[ 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 para 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 de (...)executar 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.
printf 'ab' | grep -Eq 'ab?'dentro if [ … ]?
if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi. []é um comando exatamente como grep. O ()pode não ser necessário em que comando não tenho certeza: eu adicionei-o por causa do |, depende de como Bash analisa as coisas. Se não houver |, tenho certeza que você pode escrever apenas if cmd arg arg; then.
()que parece: stackoverflow.com/questions/8965509/...
Suporte simples, isto []é, é compatível com o shell POSIX para incluir uma expressão condicional.
Parênteses duplos, isto [[]]é, é uma versão aprimorada (ou extensão) da versão POSIX padrão; isso é suportado pelo bash e outros shells (zsh, ksh).
Em bash, para comparação numérica usamos eq, ne, lte gt, com colchetes duplos para comparação, podemos usar ==, !=, <,e >literalmente.
[é sinônimo de comando de teste. Mesmo que esteja embutido no shell, ele cria um novo processo.[[ é uma nova versão aprimorada, que é uma palavra-chave, não um programa. por exemplo:
[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works
ifdeclaração, consulte mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D