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
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 surc
)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 atest
), 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
‘ sBASH_REMATCH
ottiene qualcosa di simile. Esegue anche il confronto delle stringhe, cosa che POSIX[
non fa (anche se si potrebbero immaginare modi per utilizzaresort
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
let
. ‘ non è più standard o portatile di(( a = 3 * (2 + 1) ))
(entrambi provengono daksh
e sono disponibili solo in ksh, bash e zsh) e ‘ è meno leggibile o facile da citare. Usaa=$((3 * (2 + 1)))
per essere portatile.((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 .a=1 $[a+2]
oa=1 b=2 $[a+b]
. È il loro motivo per evitare questa sintassi?