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 test
requisito adicional de um fechamento ]
. Os componentes internos [
e test
imitam a funcionalidade /bin/[
e /bin/test
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 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/sh
aponte. 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/test
estiver 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, test
exceto que test
nã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 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: 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 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 para 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 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
, lt
e 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
if
declaração, consulte mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D