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.
Como [[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:
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 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 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.
Obrigado, o link para o FAQ do bash era o que eu estava procurando (não sabia sobre essa página, obrigado).
0x89
2
Editei sua postagem com essas informações, mas [e teste são executados como internos. Os componentes internos foram projetados para substituir / bin / [e / bin / test, mas também eram necessários para reproduzir as limitações dos binários. O comando 'type [' verifica se o builtin é usado. 'que [' só procura para executáveis no caminho e é equivalente a 'tipo -P ['
klynch
133
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.
[é 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 ].
[ é 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.
[ 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ê:
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 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.
Como usar printf 'ab' | grep -Eq 'ab?'dentro if [ … ]?
MdDamian #
1
@meeDamian 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.
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 ==e !=correspondem a um padrão, em vez de uma string literal, e também ao =~operador de comparação de expressões regulares.
if
declaração, consulte mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5DRespostas:
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 aotest
requisito adicional de um fechamento]
. Os componentes internos[
etest
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 comandotype [
no Bash indica que[
é interpretado como um interno por padrão. (Nota:which [
procura apenas executáveis no PATH e é equivalente atype -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.fonte
Em resumo:
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:
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
fonte
[
é 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 quetest
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 queX
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
oub
(como+
ouindex
) e faz comparação numérica sea
e seb
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
oub
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.fonte
printf 'ab' | grep -Eq 'ab?'
dentroif [ … ]
?if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi
.[]
é um comando exatamente comogrep
. 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 apenasif 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
egt
, 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:
fonte
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
==
e!=
correspondem a um padrão, em vez de uma string literal, e também ao=~
operador de comparação de expressões regulares.fonte