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
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 emrc
)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 comtest
), 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
‘ sBASH_REMATCH
consegue algo semelhante. Ele também faz comparação de strings, o que POSIX[
não faz (embora se possa imaginar maneiras de usarsort
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
let
. Ele ‘ não é mais padrão ou portátil do que(( a = 3 * (2 + 1) ))
(ambos vêm deksh
e estão disponíveis apenas em ksh, bash e zsh) e ‘ são menos legíveis ou fáceis de citar. Usea=$((3 * (2 + 1)))
para ser portátil.((a = 3 * (2 + 1) ))
, uma para portabilidadea=$((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 .a=1 $[a+2]
oua=1 b=2 $[a+b]
. O motivo deles é evitar essa sintaxe?