Parênteses na aritmética expr: 3 * (2 + 1)

expr não parece gostar de parênteses (usado em matemática para explicitar a prioridade do operador):

expr 3 * (2 + 1) bash: syntax error near unexpected token `(" 

Como expressar a prioridade do operador no bash?

Resposta

Outra maneira de usar let bash embutido:

$ let a="3 * (2 + 1)" $ printf "%s\n" "$a" 9 

Observação

Conforme @ Stéphane Chazelas apontou , em bash você deve usar ((...)) para fazer aritmética em expr ou let para legibilidade.

Para portabilidade, use $((...)) como @Bernhard answer .

Comentários

  • +1 Ainda mais legível! Publiquei minha pergunta + resposta pensando que seria útil para meus colegas usuários do Linux, mas agora estou obtendo muitos benefícios com as outras respostas 🙂
  • Lá ‘ s nenhuma razão para usar let. Ele ‘ não é mais padrão ou portátil do que (( a = 3 * (2 + 1) )) (ambos vêm de ksh e estão disponíveis apenas em ksh, bash e zsh) e ‘ são menos legíveis ou fáceis de citar. Use a=$((3 * (2 + 1))) para ser portátil.
  • Eu ‘ não estou dizendo ‘ está errado, eu ‘ estou apenas dizendo que não deve ser usado porque existem alternativas melhores (uma para legibilidade ((a = 3 * (2 + 1) )), uma para portabilidade a=$((3 * (2 + 1)))), então ‘ não é uma nota contra você ou sua resposta, mas contra ela ser a resposta selecionada e a melhor pontuadora .
  • @St é phaneChazelas: atualizei minha resposta!
  • Sempre usei a=1 $[a+2] ou a=1 b=2 $[a+b]. O motivo deles é evitar essa sintaxe?

Resposta

Você pode usar a expansão aritmética.

echo "$(( 3 * ( 2 + 1 ) ))" 9 

Na minha opinião pessoal, parece um pouco melhor do que usar expr.

De man bash

Expansão aritmética A expansão aritmética permite a avaliação de uma expressão aritmética e a substituição do resultado. O formato da expansão aritmética é:

 $((expression)) 

A expressão é tratada como se estivesse entre aspas duplas, mas as aspas duplas entre parênteses não são tratadas especialmente. Todos os tokens na expressão passam por expansão de parâmetro, expansão de string, substituição de comando e remoção de aspas. As expansões aritméticas podem ser aninhadas.

A avaliação é realizada de acordo com as regras listadas abaixo em AVALIAÇÃO ARITMÉTICA. Se a expressão for inválida, o bash imprime uma mensagem indicando falha e nenhuma substituição ocorre.

Comentários

  • Além da legibilidade, também ‘ não requer a bifurcação de um processo extra para fazer a aritmética; ele ‘ é manipulado pelo próprio shell.
  • Observe que em shells POSIX, ele ‘ está sujeito a palavra divisão, então ‘ é um bom hábito citá-lo em contextos de lista.
  • Quando tento fazer isso no shell bash, obtenho ‘ Nome da variável ilegal. ”

Resposta

Não há razão para usar expr para aritmética em shells modernos.

POSIX define o $((...)) operador de expansão. Assim, você pode usar isso em todos os shells compatíveis com POSIX (o sh de todos os Unix-likes, dash, bash, yash, mksh, zsh, posh, ksh … ).

a=$(( 3 * (2 + 1) )) a=$((3*(2+1))) 

ksh também introduziu um let integrado no qual recebe o mesmo tipo de expressão aritmética, não se expande em algo, mas retorna um status de saída com base na resolução da expressão es para 0 ou não, como em expr:

if let "a = 3 * (2 + 1)"; then echo "$a is non-zero" fi 

No entanto, como a citação torna-o estranho e não muito legível (não na mesma medida que expr é claro), ksh também introduziu um ((...)) forma alternativa:

if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then echo "$a is non-zero and 3 > 1" fi ((a+=2)) 

que é muito mais legível e deve ser usada em seu lugar.

let e ((...)) estão disponíveis apenas em ksh, zsh e bash.A sintaxe $((...)) deve ser preferida se a portabilidade para outros shells for necessária, expr só é necessária para shells pré-POSIX semelhantes a Bourne (normalmente shell Bourne ou versões anteriores do shell Almquist).

No front não Bourne, existem alguns shells com operador aritmético integrado:

  • csh / tcsh (na verdade, o primeiro shell Unix com avaliação aritmética embutida):

    @ a = 3 * (2 + 1) 
  • akanga (com base em rc)

    a = $:"3 * (2 + 1)" 
  • como uma nota de história, a versão original do shell Almquist, conforme postado na usenet em 1989 tinha um expr incorporado (na verdade mesclado com test), mas foi removido mais tarde.

Comentários

  • Eu aprendo algo novo todos os dias com você, St é phane. Agradeço muito o seu conhecimento do shell POSIX!
  • Que tal : $((a = a*2))?
  • E se eu tiver um ponto flutuante? Minha expressão é a = $ ((-14 + 0,2 * (1 + 2 + 3))). O token de erro é ” .2 * (1 + 2 + 3) ”
  • @Blaise, então você ‘ d precisa de um shell que suporte pontos flutuantes em $((...)) como zsh, ksh93 ou yash.

Resposta

expr é um comando externo, não é uma sintaxe especial de shell. Portanto, se você deseja expr ver os caracteres especiais do shell, você precisa protegê-los da análise do shell citando-os. Além disso, expr precisa que cada número e operador seja passado como um parâmetro separado. Assim:

expr 3 \* \( 2 + 1 \) 

A menos que você esteja trabalhando em um sistema Unix antigo dos anos 1970 ou 1980, há muito pouca razão para usar expr. Antigamente, os shells não tinham uma maneira embutida de fazer aritmética e você tinha que chamar o utilitário expr. Todos os shells POSIX têm aritmética incorporada por meio da sintaxe de expansão aritmética .

O a construção $((…)) se expande para o resultado da expressão aritmética (escrita em decimal). O Bash, como a maioria dos shells, suporta apenas o módulo aritmético de inteiros 2 64 (ou módulo 2 32 para versões mais antigas do bash e alguns outros shells em máquinas de 32 bits).

O Bash oferece uma sintaxe de conveniência adicional quando você deseja realizar atribuições ou testar se uma expressão é 0, mas não se importa com o resultado. Essa construção também existe em ksh e zsh, mas não em sh simples.

((x = 3 * (2+1))) echo "$x" if ((x > 3)); then … 

Além da aritmética de inteiros, expr oferece algumas funções de manipulação de string. Elas também são incluídas nos recursos de shells POSIX, exceto por uma: expr STRING : REGEXP testa se a string corresponde à expressão regular especificada. Um shell POSIX não pode fazer isso sem ferramentas externas, mas o bash pode com [[ STRING =~ REGEXP ]] (com uma sintaxe regexp diferente expr é uma ferramenta clássica e usa BRE, bash usa ERE).

A menos que você esteja mantendo scripts que funcionam em sistemas com 20 anos, você não precisa saber que expr existiu. Use aritmética de shell.

Comentários

  • expr foo : '\(.\)' também faz extração de texto. bash ‘ s BASH_REMATCH consegue algo semelhante. Ele também faz comparação de strings, o que POSIX [ não faz (embora se possa imaginar maneiras de usar sort para isso).
  • sublinhado como espaço reservado para sintaxe — você é um Schemer, @Giles? :]
  • @RubyTuesdayDONO Não ‘ usei um sublinhado aqui. Você está interpretando mal o U + 2026 HORIZONTAL ELLIPSIS? Se sim, tente usar uma fonte maior.
  • @Giles – ok, sim, só parece um sublinhado por causa do tamanho da minha fonte. para mim, ” Schemer ” é um complemento e ‘ não é como reticências versus sublinhado muda o significado de qualquer maneira … não há necessidade de ser sarcástico: /

Resposta

Use parênteses com aspas:

expr 3 "*" "(" 2 "+" 1 ")" 9 

As aspas evitam que o bash interprete os parênteses como sintaxe bash.

Comentários

  • O que Nicolas ilustra, mas não explica, é que os tokens na linha de comando expr devem ser separados por espaços; então; por exemplo, expr 3 "*" "(2" "+" "1)" não funcionará . (Além disso, BTW, você provavelmente não precisa citar o +.)
  • Os parênteses não são ‘ palavras-chave como while e [[, eles ‘ re sintaxe. Se fossem palavras-chave, não ‘ seriam interpretadas como tal nos argumentos de comando. Você precisa de aspas para que o bash não ‘ as analise, mas veja uma string literal.

Resposta

Se você tiver bc ..

echo "3 * (2 + 1)"|bc 9 

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *