expr
non sembra che la parentesi (usata in matematica per esplicita priorità dell'operatore):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
Come esprimere la priorità dell'operatore in bash?
expr
non sembra che la parentesi (usata in matematica per esplicita priorità dell'operatore):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
Come esprimere la priorità dell'operatore in bash?
Risposte:
Un altro modo di usare let
bash builtin:
$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9
Nota
Come ha sottolineato @ Stéphane Chazelas , bash
dovresti usare ((...))
l'aritmetica expr
o la let
leggibilità.
Per la portabilità, utilizzare $((...))
come risposta @Bernhard .
let
. Non è più standard o portatile di (( a = 3 * (2 + 1) ))
(entrambi provengono ksh
e sono disponibili solo in ksh, bash e zsh) ed è meno leggibile o facile da citare. Usa a=$((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 è la risposta selezionata e capocannoniere.
a=1 $[a+2]
o a=1 b=2 $[a+b]
. È la loro ragione per evitare quella sintassi?
È invece possibile utilizzare l'espansione aritmetica.
echo "$(( 3 * ( 2 + 1 ) ))"
9
Secondo me, sembra un po 'più bello dell'uso expr
.
A partire dal man bash
Espansione aritmetica L'espansione aritmetica consente la valutazione di un'espressione aritmetica e la sostituzione del risultato. Il formato per l'espansione aritmetica è:
$((expression))
L'espressione viene trattata come se fosse racchiusa tra virgolette doppie, ma una virgoletta doppia tra parentesi non viene trattata in modo speciale. Tutti i token nell'espressione subiscono l'espansione dei parametri, l'espansione della stringa, la sostituzione dei comandi e la rimozione delle virgolette. Le espansioni aritmetiche possono essere nidificate.
La valutazione viene eseguita secondo le regole elencate di seguito in VALUTAZIONE ARITMETICA. Se l'espressione non è valida, bash stampa un messaggio che indica l'errore e non si verifica alcuna sostituzione.
Non c'è motivo di usare l' expr
aritmetica nelle conchiglie moderne.
POSIX definisce l' $((...))
operatore di espansione. Quindi puoi usarlo in tutte le shell compatibili con POSIX (le più sh
moderne di tipo Unix, dash, bash, yash, mksh, zsh, posh, ksh ...).
a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))
ksh
ha anche introdotto un let
builtin a cui viene passato lo stesso tipo di espressione aritmetica, che non si espande in qualcosa ma restituisce uno stato di uscita in base al fatto che l'espressione si risolva in 0 oppure no, come in expr
:
if let 'a = 3 * (2 + 1)'; then
echo "$a is non-zero"
fi
Tuttavia, poiché la citazione la rende scomoda e poco leggibile (non nella stessa misura expr
ovviamente), ha ksh
anche introdotto una ((...))
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 usato invece.
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 (in genere la shell Bourne o le prime versioni della shell Almquist).
Sul fronte non Bourne, ci sono alcune conchiglie con operatore aritmetico incorporato:
csh
/ tcsh
(in realtà la prima shell Unix con valutazione aritmetica integrata):
@ a = 3 * (2 + 1)
akanga
(basato su rc
)
a = $:'3 * (2 + 1)'
come nota storica, la versione originale della shell Almquist, pubblicata su usenet nel 1989, aveva un expr
builtin (effettivamente unito a test
), ma è stata rimossa in seguito.
: $((a = a*2))
?
$((...))
come zsh, ksh93 o yash.
expr
è un comando esterno, non è una sintassi speciale della shell. Pertanto, se si desidera expr
visualizzare i caratteri speciali della shell, è necessario proteggerli dall'analisi della shell citandoli. Inoltre, expr
ogni numero e operatore deve essere passato come parametro separato. Così:
expr 3 \* \( 2 + 1 \)
A meno che tu non stia lavorando su un sistema unix antico degli anni '70 o '80, ci sono pochissime ragioni per usarlo expr
. Ai vecchi tempi, le shell non avevano un modo integrato per eseguire l'aritmetica e invece si doveva chiamare l' expr
utilità. Tutte le shell POSIX hanno un'aritmetica integrata tramite la sintassi di espansione aritmetica .
echo "$((3 * (2 + 1)))"
Il costrutto si $((…))
espande al risultato dell'espressione aritmetica (scritta in decimale). Bash, come la maggior parte delle shell, supporta solo l'aritmetica 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 un'ulteriore sintassi di convenienza quando si desidera eseguire compiti o verificare se un'espressione è 0 ma non ci si preoccupa del risultato. Questo costrutto esiste anche in ksh e zsh ma non in sh.
((x = 3 * (2+1)))
echo "$x"
if ((x > 3)); then …
Oltre all'aritmetica dei numeri interi, expr
offre alcune funzioni di manipolazione delle stringhe. Anche questi sono riassunti dalle caratteristiche delle shell POSIX, tranne uno: expr STRING : REGEXP
verifica se la stringa corrisponde al regexp specificato. Una shell POSIX non può farlo senza strumenti esterni, ma bash può con [[ STRING =~ REGEXP ]]
(con una diversa sintassi regexp - expr
è uno strumento classico e usa BRE, bash usa ERE).
A meno che tu non stia mantenendo script eseguiti su sistemi di 20 anni, non devi sapere che siano expr
mai esistiti. Usa l'aritmetica della shell.
expr foo : '\(.\)'
fa anche l'estrazione del testo. bash
's BASH_REMATCH
Raggiunge qualcosa di simile. Fa anche il confronto delle stringhe, cosa che POSIX [
non fa (sebbene si possano immaginare modi per usarlo sort
).
Usa le parentesi tra virgolette:
expr 3 '*' '(' 2 '+' 1 ')'
9
Le virgolette impediscono a bash di interpretare la parentesi come sintassi di bash.
expr
riga di comando devono essere separati da spazi; così; per esempio, expr 3 "*" "(2" "+" "1)"
non funzionerà . (Inoltre, probabilmente non è necessario citare il +
.)
while
e [[
sono sintassi. Se fossero parole chiave, non verrebbero interpretate come tali negli argomenti dei comandi. Hai bisogno di virgolette in modo che bash non le analizzi ma veda invece una stringa letterale.