Se [é um construído e [[é uma palavra-chave, então o que é ((?

5

De acordo com esta postagem , [ é uma versão interna e [[ é uma palavra-chave. Como eles podem ser considerados como comando, tudo após [ e [[ é considerado como argumentos de comando e deve ser separado por espaços, até que eles atinjam o argumento final ] e ]]

Mas qual é o tipo de (( ?

type ((

dará um erro:

 bash: syntax error near unexpected token '('. 

Descobri que os espaços não são relevantes dentro de (( )) .

echo $((1+1))
echo $(( 1+1))
echo $(( 1+1 ))
echo $(( 1+  1))
echo $(( 1  +  1  ))

são todos iguais

resumo

de acordo com o documento padrão POSIX: seção Comandos de agrupamento

If a character sequence beginning with "((" would be parsed by the shell as an arithmetic expansion if preceded by a '$', shells which implement an extension whereby "((expression))" is evaluated as an arithmetic expression may treat the "((" as introducing as an arithmetic evaluation instead of a grouping command. A conforming application shall ensure that it separates the two leading '(' characters with white space to prevent the shell from performing an arithmetic evaluation.

E a avaliação aritmética dentro de ((...)) está em conformidade com o estilo C. Então o espaço não é relevante dentro de ((...))

    
por user15964 26.04.2017 / 16:39

2 respostas

3

(( não é uma palavra. Ao contrário de [ e [[ , não faz parte da lista de palavras que constitui um comando. A melhor maneira de pensar nisso é como pontuação. Na verdade, são dois caracteres de pontuação, que podem ou não ser combinados em um único token, dependendo do contexto. É semelhante a coisas como >& e || a esse respeito. Os caracteres de pontuação são tratados de maneira ad-hoc pelo lexer / analisador do shell.

(( é metade de um operador, a outra metade sendo )) . Juntos, eles fazem o operador de expressão aritmética, que tem uma sintaxe de "correção". A estrutura gramatical das linguagens shell, como bash, não segue a sintaxe tradicional da linguagem de programação (por exemplo, há laços muito strongs entre análise lexical e análise gramatical, porque os caracteres de pontuação têm um significado que depende do contexto gramatical). nem sempre são palavras que se encaixam perfeitamente.

type só pode fornecer informações sobre palavras que podem aparecer em comandos simples e sobre palavras-chave, não sobre como o lexer / analisador do shell funciona.

    
por 27.04.2017 / 02:34
2

No bash, os três elementos que você pergunta são semelhantes aos comandos:

  1. Todos os [ [[ e (( podem ser a primeira "palavra" de uma linha de comando. É claro que o resto da linha deve corresponder à sintaxe válida.
  2. Todos têm ajuda do próprio shell:

    A [ :

    $ help [
    [: [ arg... ]
        Evaluate conditional expression.
    
        This is a synonym for the "test" builtin, but the last
        argument must be a literal ']', to match the opening '['.
    

    A [[ :

    $ help [[
    [[ ... ]]: [[ expression ]]
        Execute conditional command.
        …
        …
    

    E um (( (deve ser citado para ser corretamente reconhecido):

    $ help '(('
    (( ... )): (( expression ))
        Evaluate arithmetic expression.
    
        The EXPRESSION is evaluated according to the rules for arithmetic
        evaluation.  Equivalent to "let EXPRESSION".
    
        Exit Status:
        Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise. 
    

No entanto, A (( é realmente um iniciador de um "Comando Composto".
Pode se estender por várias linhas, muito parecido com um if :

$ ((
> 2+2
> ))

$ if
> true
> then
> echo yes
> fi
yes

Não pode ser dividido em dois caracteres (coloque um espaço entre os dois ( ) e permaneça uma "Expressão Aritmética". O uso de um espaço é necessário no POSIX para garantir a análise correta de Grouping Commands . Ou seja: converta o (( em dois% independentes (list) .

Esse é o mesmo efeito que dividir um if nos caracteres i e f (altera a maneira como o shell interpreta os comandos):

$ i    f
i: command not found

Se (( for dividido, ele se tornará um par de (list) :

(list) list is executed in a subshell environment

E (( não requer espaços ao redor para ser reconhecido (diferente de if ):

$ (w);((a=33))&&((b=34));echo $a $b
… …
33 34

O (( divide a linha em "tokens" por si só.

A chamada de uma pontuação " (( " é tão razoável quanto chamar uma if "pontuação".

Você pode pesquisar dentro de man bash por \(\( ou usar esta linha de pesquisa (pressione n para acessar as próximas instâncias uma vez dentro do manual):

$ LESS=+/'\(\(' man bash

No entanto, também faz parte de uma "Expansão Aritmética", que é iniciada pela presença de um $ primeiro e faz parte do (também) "Comando Composto":

for (( expr1 ; expr2 ; expr3 )) ; do list ; done

Também é importante observar que um simples ( é um metacaractere (divisor de linhas de comando em palavras antes de iniciar a análise). Portanto, um ( com um espaço significa algo diferente de dois (( juntos.

Em ksh, a sintaxe válida a (( pode ser parte do for loop, também, é definida como algo diferente de um comando simples ((expression)) , parte de uma Expansão Aritmética $((…)) e parte do posicionamento FD <#((expr)) e >#((expr)) .

Em zsh, (( … )) é definido como se fosse um argumento de let e é considerado um argumento "cotado" avaliado como uma expressão aritmética. (Parece o mesmo que para ksh ou bash se você me pedir uma opinião). Além disso, em zsh há uma diferença para "Qualificadores Globais", em que um% (( significa algo diferente:

for example (^x)', can be forced to be treated as part of the glob pattern by doubling the parentheses, in this case producing((^x))'.

Não consegui encontrar uma regra de trabalho simples para analisar esse uso.

    
por 27.04.2017 / 01:15