it-swarm-pt.tech

Qual é a diferença entre colchetes duplos e únicos 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.

451
0x89

Existem várias diferenças. Na minha opinião, alguns dos mais importantes são:

  1. [ é um builtin no Bash e em muitas outras conchas modernas. O builtin [ é semelhante a test com o requisito adicional de um fechamento ]. Os builtins [ e test 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. Executando o comando type [ no Bash indica que [ é interpretado como um interno por padrão. (Nota: which [ procura apenas executáveis ​​no caminho [~ # ~] [~ # ~] e é equivalente a type -p [)
  2. [[ não é tão compatível, não necessariamente funcionará com o que seja /bin/sh aponta para. Assim [[ é a opção Bash/Zsh/Ksh mais moderna.
  3. Porque [[ é incorporado ao Shell e não possui requisitos herdados, você não precisa se preocupar com a divisão do Word com base nos [~ # ~] ifs [~ # ~] variável para atrapalhar as variáveis ​​avaliadas em uma sequência de caracteres 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 FAQ:: Qual é a diferença entre test, [e [[? . De fato, se você estiver falando sério sobre scripts bash, recomendo a leitura de todo o wiki , incluindo as perguntas frequentes, armadilhas e o guia. A seção de teste da seção do guia explica estes diferenças também e por que os autores pensam [[ é uma escolha melhor se você não precisa se preocupar em ser tão portátil. Os principais motivos são:

  1. Você não precisa se preocupar em citar o lado esquerdo do teste para que ele seja lido como uma variável.
  2. Você não precisa escapar menos e maior que < > com barras invertidas para que não sejam avaliadas como redirecionamento de entrada, o que pode realmente atrapalhar algumas coisas substituindo arquivos. Isso novamente remonta a [[ sendo um embutido. Se [(test) for um programa externo, o Shell precisaria abrir uma exceção na forma como avalia < e > somente se /bin/test está sendo chamado, o que realmente não faria sentido.
325
Kyle Brandt

Em resumo:

[é um bash interno

[[]] são bash Palavras-chave

Palavras-chave: As palavras-chave são bastante parecidas com as incorporadas, 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

138
abhiomkar

Diferenças de comportamento

Algumas diferenças no Bash 4.3.11:

  • Extensão POSIX vs Bash:

  • comando regular vs magia

    • _[_ é apenas um comando regular com um nome estranho.

      _]_ é apenas um argumento de _[_ que impede que outros argumentos sejam usados.

      O Ubuntu 16.04 realmente tem um executável para ele em _/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, _<_ é redirecionamento, _&&_ e _||_ concatenam vários comandos, _( )_ gera subshells, a menos que seja escapado por _\_, e a expansão do Word acontece como de costume.

    • _[[ X ]]_ é uma construção única que faz com que X seja analisado magicamente. _<_, _&&_, _||_ e _()_ são tratados especialmente e as regras de divisão do Word são diferentes.

      Também existem 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-e-Shell-palavra-chave

  • _<_

  • _&&_ e _||_

    • _[[ a = a && b = b ]]_: verdadeiro, lógico e
    • _[ a = a && b = b ]_: erro de sintaxe, _&&_ analisado como um separador de comandos AND _cmd1 && 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 _()_ está obsoleto pelo POSIX
    • _{ [ a = a ] || [ a = b ]; } && [ a = b ]_ POSIX equivalente5
  • Divisã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á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 ao POSIX
  • _=_

    • _[[ ab = a? ]]_: true, porque sim correspondência de padrão (_* ? [_ são mágicos). Não é expandido para arquivos no diretório atual.
    • _[ ab = a? ]_: _a?_ glob 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 os mesmos em _[_ e _[[_, mas _==_ é uma extensão do Bash.
    • case ab in (a?) echo match; esac: equivalente a POSIX
    • _[[ ab =~ 'ab?' ]]_: false4, perde mágica com _''_
    • _[[ ab? =~ 'ab?' ]]_: verdadeiro
  • _=~_

    • _[[ ab =~ ab? ]]_: true, POSIX expressão regular estendida corresponde, _?_ não é expandido
    • _[ 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 a POSIX.

Recomendação : use sempre _[]_.

Existem equivalentes POSIX para cada construção _[[ ]]_ que eu já vi.

Se você usar _[[ ]]_, você:

  • perder portabilidade
  • forçar o leitor a aprender os meandros de outra extensão do bash. _[_ é apenas um comando regular com um nome estranho, sem semântica especial envolvida.

¹ Inspirado no equivalente _[[...]]_ no Korn Shell

² mas falha para alguns valores de a ou b (como _+_ ou index) e faz comparação numérica se a e b parecem números inteiros decimais. _expr "x$a" '<' "x$b"_ funciona em torno de ambos.

³ e também falha em alguns valores de a ou b como _!_ ou _(_.

4 no bash 3.2 e acima e a compatibilidade fornecida com o bash 3.1 não está ativada (como com _BASH_COMPAT=3.1_)

5 embora o agrupamento (aqui com o grupo de comandos _{...;}_ em vez de _(...)_ que executaria um subshell desnecessário) não seja necessário, pois os operadores _||_ e _&&_ Shell (em oposição a os operadores _||_ e _&&_ _[[...]]_ ou os operadores _-o_/_-a_ _[_) têm precedência igual. Então _[ a = a ] || [ a = b ] && [ a = b ]_ seria equivalente.

colchete único i.e. [] é compatível com o POSIX Shell para incluir uma expressão condicional.

colchetes duplos i.e. [[]] é uma versão aprimorada (ou extensão) da versão POSIX padrão, suportada pelo bash e outros shells (zsh, ksh).

No bash, para comparação numérica, usamos eq, ne, lt e gt, com colchetes duplos para comparação, podemos usar ==, !=, <, e > literalmente.

  • [ é sinônimo de comando de teste. Mesmo se incorporado ao Shell, 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
6
Premraj

Com base em uma leitura rápida das seções relevantes da página de manual, a principal diferença parece ser que o == e != operadores correspondem contra um padrão, em vez de uma string literal, e também que existe o =~ operador de comparação regex.

4
womble