Estou um pouco confuso sobre o que esses operadores fazem de maneira diferente quando usados no bash (colchetes, colchetes duplos, parênteses e parênteses duplos).
[[ , [ , ( , ((
Já vi pessoas usá-las em declarações if como esta:
if [[condition]]
if [condition]
if ((condition))
if (condition)
Respostas:
Uma
if
declaração normalmente se parece comA
then
cláusula é executada se o código de saídacommands1
for zero. Se o código de saída for diferente de zero, aelse
cláusula será executada.commands1
pode ser simples ou complexo. Ele pode, por exemplo, ser uma sequência de uma ou mais condutas separadas por um dos operadores;
,&
,&&
, ou||
. Asif
condições mostradas abaixo são apenas casos especiais decommands1
:if [ condition ]
Este é o
test
comando tradicional do shell . Está disponível em todos os shells POSIX. O comando test define um código de saída e aif
instrução age de acordo. Testes típicos são se existe um arquivo ou se um número é igual a outro.if [[ condition ]]
Esta é uma nova variação atualizada
test
do ksh que o bash e o zsh também suportam. Estetest
comando também define um código de saída e aif
instrução age de acordo. Entre seus recursos estendidos, ele pode testar se uma string corresponde a uma expressão regular.if ((condition))
Outra extensão ksh que o bash e o zsh também suportam. Isso executa aritmética. Como resultado da aritmética, um código de saída é definido e a
if
instrução age de acordo. Retorna um código de saída zero (verdadeiro) se o resultado do cálculo aritmético for diferente de zero. Assim[[...]]
, este formulário não é POSIX e, portanto, não é portátil.if (command)
Isso executa o comando em um subshell. Quando o comando é concluído, ele define um código de saída e a
if
instrução age de acordo.Um motivo comum para usar um subshell como este é para limitar efeitos colaterais de
command
secommand
necessário atribuições de variáveis ou outras alterações no ambiente do shell. Essas alterações não permanecem após a conclusão do subshell.if command
O comando é executado e a
if
instrução age de acordo com seu código de saída.fonte
[
na verdade, é um comando ou símbolo binário, não interno. Geralmente vive em/bin
.[
é construído como estátest
. Existem versões binárias disponíveis por motivos de compatibilidade. Confirahelp [
ehelp test
.$((
ou seja, a expansão aritmética é e é fácil confundi-los Muitas vezes, uma solução é usar algo como.[ $((2+2)) -eq 4 ]
A fazer uso de aritmética em declarações conditinal(…)
parênteses indicam um subshell . O que há dentro deles não é uma expressão como em muitos outros idiomas. É uma lista de comandos (assim como parênteses externos). Esses comandos são executados em um subprocesso separado, portanto, qualquer redirecionamento, atribuição, etc. realizado dentro dos parênteses não tem efeito fora dos parênteses.$(…)
é uma substituição de comando : há um comando entre parênteses e a saída do comando é usada como parte da linha de comando (após expansões extras, a menos que a substituição seja entre aspas duplas, mas isso é outra história ) .{ … }
chaves são como parênteses, pois agrupam comandos, mas apenas influenciam a análise, não o agrupamento. O programax=2; { x=4; }; echo $x
imprime 4, enquanto quex=2; (x=4); echo $x
imprime 2. (Também chaves entre palavras-chave precisam ser delimitadas e encontradas na posição de comando (daí o espaço depois{
e o;
anterior}
), enquanto os parênteses não. Isso é apenas uma peculiaridade de sintaxe.)${VAR}
é uma expansão de parâmetro , expandindo para o valor de uma variável, com possíveis transformações extras. Oksh93
shell também suporta${ cmd;}
como forma de substituição de comando que não gera um subshell.((…))
parênteses duplos cercam uma instrução aritmética , isto é, uma computação em números inteiros, com uma sintaxe semelhante a outras linguagens de programação. Essa sintaxe é usada principalmente para atribuições e em condicionais. Isso existe apenas no ksh / bash / zsh, não no sh simples.$((…))
, que se expandem para o valor inteiro da expressão.[ … ]
colchetes simples cercam expressões condicionais . Expressões condicionais são construídas principalmente em operadores , como-n "$variable"
para testar se uma variável está vazia e-e "$file"
para testar se existe um arquivo. Observe que você precisa de um espaço ao redor de cada operador (por exemplo[ "$x" = "$y" ]
, não), e um espaço ou um caractere como[ "$x"="$y" ]
;
dentro e fora dos colchetes (por exemplo[ -n "$foo" ]
, não).[-n "$foo"]
[[ … ]]
colchetes duplos são uma forma alternativa de expressões condicionais no ksh / bash / zsh com alguns recursos adicionais, por exemplo, você pode escrever[[ -L $file && -f $file ]]
para testar se um arquivo é um link simbólico para um arquivo regular, ao passo que colchetes simples exigem[ -L "$file" ] && [ -f "$file" ]
. Consulte Por que a expansão de parâmetros com espaços sem aspas funciona entre colchetes duplos [[mas não entre colchetes únicos]? para saber mais sobre esse assunto.No shell, todo comando é um comando condicional: todo comando tem um status de retorno que é 0, indicando sucesso ou um número inteiro entre 1 e 255 (e potencialmente mais em alguns shells), indicando falha. O
[ … ]
comando (ou[[ … ]]
formulário de sintaxe) é um comando específico que também pode ser escritotest …
e é bem-sucedido quando um arquivo existe, ou quando uma string está vazia, ou quando um número é menor que outro, etc. O((…))
formulário de sintaxe é bem-sucedido quando um número é diferente de zero. Aqui estão alguns exemplos de condicionais em um script de shell:Teste se
myfile
contém a sequênciahello
:Se
mydir
for um diretório, mude para ele e faça o seguinte:Teste se existe um arquivo chamado
myfile
no diretório atual:O mesmo, mas também incluindo links simbólicos pendentes:
Teste se o valor de
x
(que é assumido como numérico) é pelo menos 2, portably:Teste se o valor de
x
(que é assumido como numérico) é pelo menos 2, em bash / ksh / zsh:fonte
-a
vez de&&
, por isso, pode-se escrever:[ -L $file -a -f $file ]
, que é o mesmo número de caracteres dentro dos colchetes, sem extra[
e]
...-a
e-o
são problemáticos porque podem levar a análises incorretas se alguns dos operandos envolvidos parecerem operadores. É por isso que não os mencionei: eles têm vantagem zero e nem sempre funcionam. E nunca escreva expansões de variáveis não citadas sem uma boa razão: tudo[[ -L $file -a -f $file ]]
bem, mas com colchetes simples você precisa[ -L "$file" -a -f "$file" ]
(o que é bom, por exemplo, se$file
sempre começa com/
ou./
).[[ -L $file && -f $file ]]
(não-a
com a[[...]]
variante).Na documentação do bash :
Em outras palavras, verifique se o que acontece na 'lista' (como a
cd
) não tem efeito fora do(
e)
. A única coisa que vai vazar é o código de saída do último comando ou comset -e
o primeiro comando que gera um erro (excepto alguns, comoif
,while
, etc.)Esta é uma extensão do bash, permitindo que você faça contas. É um pouco semelhante ao uso
expr
sem todas as limitações deexpr
(como ter espaços em todos os lugares, escapar*
etc.)Isso oferece um teste avançado para comparar seqüências de caracteres, números e arquivos, um pouco como
test
ofertas, mas mais poderoso.Este chama
test
. Na verdade, antigamente,[
havia um link simbólico paratest
. Funciona da mesma maneira e você tem as mesmas limitações. Como um binário sabe o nome com o qual foi iniciado, o programa de teste pode analisar parâmetros até encontrar um parâmetro]
. Truques divertidos do Unix.Observe que, no caso de
bash
,[
etest
são funções internas (como mencionado em um comentário), ainda assim as mesmas limitações se aplicam.fonte
test
e,[
é claro, sejam comandos integrados no Bash, mas é provável que também exista um binário externo.[
não é um link simbólico paratest
a maioria dos sistemas modernos.strings /usr/bin/test
mostre que também tem o texto de ajuda, não sei o que dizer.test
comando deva obviamente existir como um comando independente baseado em arquivo pelo padrão, nada nele declara que sua[
variante precisa ser implementada dessa maneira também. Por exemplo, Solaris 11 não fornece qualquer[
executável, mas é, no entanto, totalmente compatível com os padrões POSIX[
vs[[
Esta resposta cobrirá o subconjunto
[
vs[[
da pergunta.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
expr
à resposta. O termo "extensão Bash" não significa que o Bash foi o primeiro shell a adicionar alguma sintaxe, já que aprender POSIX sh vs Bash já é suficiente para me deixar louco.man test
se você tentouman [
e se perdeu. Isso explicará a variante POSIX.Alguns exemplos:
Teste tradicional:
test
e[
são comandos como qualquer outro, portanto, a variável é dividida em palavras, a menos que esteja entre aspas.Teste de novo estilo
[[ ... ]]
é uma construção de shell especial (mais recente), que funciona de maneira um pouco diferente, a coisa mais óbvia é que ela não divide variáveis de palavras:Alguma documentação aqui
[
e[[
aqui .Teste aritmético:
Comandos "normais":
Todas as opções acima agem como comandos normais e
if
podem executar qualquer comando:Múltiplos comandos:
Ou podemos usar vários comandos. O agrupamento de um conjunto de comandos os
( ... )
executa no subshell, criando uma cópia temporária do estado do shell (diretório de trabalho, variáveis). Se precisarmos executar algum programa temporariamente em outro diretório:fonte
Comandos de agrupamento
( list )
Colocar uma lista de comandos entre parênteses causa a criação de um ambiente de subshell, e cada um dos comandos na lista é executado nesse subshell. Como a lista é executada em um subshell, as atribuições de variáveis não permanecem em vigor após a conclusão do subshell.{ list; }
Colocar uma lista de comandos entre chaves faz com que a lista seja executada no contexto atual do shell . Nenhum subshell é criado. É necessário o ponto e vírgula (ou nova linha) a seguir. FonteConstruções condicionais
Suporte único ou seja,
[]
Para efeitos de comparação
==, !=, <,
e>
e deve ser usada e, para comparação numéricoeq, ne,lt
egt
deve ser usado.Suportes avançados ie
[[]]
Em todos os exemplos acima, usamos apenas colchetes únicos para incluir a expressão condicional, mas o bash permite colchetes duplos, que serve como uma versão aprimorada da sintaxe de colchetes únicos.
Para comparação
==, !=, <,
e>
pode usar 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.[[
é entendido porKorn
eBash
.Fonte
fonte