Parentesi in aritmetica expr: 3 * (2 + 1)

expr sembra non gradire la parentesi (usata in matematica alla priorità delloperatore esplicito):

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

Come esprimere la priorità delloperatore in bash?

Risposta

Un altro modo per utilizzare let bash builtin:

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

Nota

Come @ Stéphane Chazelas ha sottolineato , in bash dovresti utilizzare ((...)) per eseguire operazioni aritmetiche su expr o let per la leggibilità.

Per la portabilità, utilizza $((...)) come @Bernhard answer .

Commenti

  • +1 Ancora più leggibile! Ho pubblicato la mia domanda + risposta solo pensando che sarebbe stato utile per i miei colleghi utenti Linux, ma ora sto ottenendo molti vantaggi dalle altre risposte 🙂
  • Ecco ‘ non cè motivo di utilizzare let. ‘ non è più standard o portatile di (( a = 3 * (2 + 1) )) (entrambi provengono da ksh e sono disponibili solo in ksh, bash e zsh) e ‘ è meno leggibile o facile da citare. Usa a=$((3 * (2 + 1))) per essere portatile.
  • ‘ non lo dico ‘ è sbagliato, ‘ sto solo dicendo che non dovrebbe essere usato perché ci sono alternative migliori (una per la leggibilità ((a = 3 * (2 + 1) )), una per la portabilità a=$((3 * (2 + 1)))), quindi ‘ non è una nota contro di te o la tua risposta, ma contro che sia la risposta selezionata e il miglior realizzatore .
  • @St é phaneChazelas: ho aggiornato la mia risposta!
  • Ho sempre usato a=1 $[a+2] o a=1 b=2 $[a+b]. È il loro motivo per evitare questa sintassi?

Risposta

Puoi invece utilizzare lespansione aritmetica.

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

A mio parere personale, questo sembra un po più carino rispetto allutilizzo di expr.

Da man bash

Espansione aritmetica Lespansione aritmetica consente la valutazione di unespressione aritmetica e la sostituzione del risultato. Il formato per lespansione aritmetica è:

 $((expression)) 

Lespressione viene trattata come se fosse tra virgolette doppie, ma le virgolette doppie tra parentesi non vengono trattate in modo speciale. Tutti i token nellespressione subiscono lespansione dei parametri, lespansione delle stringhe, la sostituzione dei comandi e la rimozione delle virgolette. Le espansioni aritmetiche possono essere annidate.

La valutazione viene eseguita in base alle regole elencate di seguito in VALUTAZIONE ARITMETICA. Se lespressione non è valida, bash stampa un messaggio che indica lerrore e non si verifica alcuna sostituzione.

Commenti

  • A parte la leggibilità, ‘ non richiede il fork di un processo aggiuntivo per eseguire laritmetica; ‘ è gestito dalla shell stessa.
  • Nota che nelle shell POSIX, ‘ è soggetto a parola splitting, quindi ‘ è una buona abitudine citarlo in contesti di lista.
  • Quando provo questo nella shell bash ottengo ‘ Nome variabile non valido. ”

Risposta

Non cè motivo di utilizzare expr per laritmetica nelle shell moderne.

POSIX definisce $((...)) operatore di espansione. Quindi puoi usarlo in tutte le shell compatibili con POSIX (il sh di tutti i moderni Unix-like, dash, bash, yash, mksh, zsh, posh, ksh … ).

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

ksh ha anche introdotto un let integrato che viene passato lo stesso tipo di espressione aritmetica, non si espande in qualcosa ma restituisce uno stato di uscita in base al fatto che lespressione risolva es a 0 o no, come in expr:

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

Tuttavia, poiché la citazione lo rende imbarazzante e non molto leggibile (non nella stessa misura di expr ovviamente), ksh ha anche introdotto un ((...)) forma alternativa:

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

che è molto più leggibile e dovrebbe essere utilizzata al suo posto.

let e ((...)) sono disponibili solo in ksh, zsh e bash.La sintassi $((...)) dovrebbe essere preferita se è necessaria la portabilità ad altre shell, expr è necessaria solo per shell tipo Bourne pre-POSIX (tipicamente la shell Bourne o le prime versioni della shell Almquist).

Sul fronte non Bourne, ci sono alcune shell con operatore aritmetico incorporato:

  • csh / tcsh (in realtà la prima shell Unix con valutazione aritmetica incorporata):

    @ a = 3 * (2 + 1) 
  • akanga (basato su rc)

    a = $:"3 * (2 + 1)" 
  • come nota sulla storia, la versione originale della shell Almquist, pubblicata su Usenet nel 1989, aveva un expr incorporato (in realtà unito a test), ma è stato rimosso in seguito.

Commenti

  • Imparo qualcosa di nuovo ogni giorno da te, St é phane. Apprezzo molto la tua conoscenza della shell POSIX!
  • Che ne dici di : $((a = a*2))?
  • E se avessi una virgola mobile? La mia espressione è a = $ ((-14 + 0.2 * (1 + 2 + 3))). Il token di errore è ” .2 * (1 + 2 + 3) ”
  • @Blaise, quindi tu ‘ d necessita di una shell che supporti i punti mobili in $((...)) come zsh, ksh93 o yash.

Risposta

expr è un comando esterno, non è una sintassi speciale della shell. Pertanto, se vuoi che expr veda i caratteri speciali della shell, devi proteggerli dallanalisi della shell citandoli. Inoltre, expr richiede che ogni numero e operatore venga passato come parametro separato. Quindi:

expr 3 \* \( 2 + 1 \) 

A meno che tu “non stia lavorando su un antico sistema unix degli anni 70 o 80, ci sono pochissime ragioni per utilizzare expr. Ai vecchi tempi, le shell non avevano un modo integrato per eseguire operazioni aritmetiche e dovevi invece chiamare lutilità expr. Tutte le shell POSIX hanno aritmetica incorporata tramite la sintassi espansione aritmetica .

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

Il costruire $((…)) si espande al risultato dellespressione aritmetica (scritta in decimale). Bash, come la maggior parte delle shell, supporta solo laritmetica intera modulo 2 64 (o modulo 2 32 per le versioni precedenti di bash e alcune altre shell su macchine a 32 bit).

Bash offre una sintassi aggiuntiva per praticità quando si desidera eseguire assegnazioni o verificare se unespressione è 0 ma non si preoccupa del risultato. Questo costrutto esiste anche in ksh e zsh ma non in semplice sh.

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

Oltre allaritmetica dei numeri interi, expr offre alcune funzioni di manipolazione delle stringhe. Anche queste sono riassunte dalle caratteristiche delle shell POSIX, eccetto una: expr STRING : REGEXP verifica se la stringa corrisponde allespressione regolare specificata. Una shell POSIX non può farlo senza strumenti esterni, ma bash può farlo con [[ STRING =~ REGEXP ]] (con una sintassi regexp diversa expr è uno strumento classico e usa BRE, bash usa ERE).

A meno che tu non stia mantenendo gli script che funzionano su sistemi vecchi di 20 anni, non è necessario sapere che expr è mai esistito. Usa laritmetica della shell.

Commenti

  • expr foo : '\(.\)' esegue anche lestrazione del testo. bash ‘ s BASH_REMATCH ottiene qualcosa di simile. Esegue anche il confronto delle stringhe, cosa che POSIX [ non fa (anche se si potrebbero immaginare modi per utilizzare sort per questo).
  • trattino di sottolineatura come segnaposto di sintassi — sei uno Schemer, @Giles? :]
  • @RubyTuesdayDONO ‘ non ho usato un trattino basso qui. Stai interpretando male lELLISSI ORIZZONTALE U + 2026? Se è così, prova a usare un carattere più grande.
  • @Giles – ok, sì, sembra solo un trattino basso a causa della mia dimensione del carattere. per me, ” Schemer ” è un complemento e ‘ non è come i puntini di sospensione rispetto al trattino basso cambia comunque il significato … non cè bisogno di essere irriverenti su di esso: /

Risposta

Usa parentesi con citazioni:

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

Le virgolette impediscono a bash di interpretare le parentesi come sintassi bash.

Commenti

  • Ciò che Nicolas illustra ma non spiega è che i token sulla riga di comando expr devono essere separati da spazi; così; ad esempio, expr 3 "*" "(2" "+" "1)" non funzionerà . (Inoltre, a proposito, probabilmente non è necessario citare +.)
  • Le parentesi non sono ‘ t parole chiave come while e [[, sono ‘ sulla sintassi. Se fossero parole chiave, non sarebbero ‘ interpretate come tali negli argomenti del comando. Hai bisogno delle virgolette in modo che bash non ‘ le analizzi ma visualizzi una stringa letterale.

Risposta

Se hai bc ..

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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *