Più operatori logici, ((A || B) & & C) e “ errore di sintassi vicino al token imprevisto ”

Sto lavorando con Bash 3 e sto provando a formare un condizionale. In C / C ++, è semplicissimo: ((A || B) && C). In Bash, non è così (penso che gli autori di Git debbano aver contribuito a questo codice prima di passare ad altri sforzi).

Questo non funziona. Tieni presente che <0 or 1> non è una stringa letterale; significa 0 o 1 (generalmente deriva da grep -i).

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eqe "0" ]; then ... fi 

Risulta in:

line 322: syntax error near unexpected token `[[" 

Ho quindi provato:

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ ([ "$A" -eq "0" ]) || ([ "$B" -ne "0" ]) ] && [ "$C" -eq "0" ]; then ... fi 

risulta in:

line 322: syntax error near unexpected token `[[" 

Parte del problema è che i risultati della ricerca sono esempi banali e non esempi più complessi con condizionali composti.

Come eseguo un semplice ((A || B) && C) in Bash?


Sono pronto a srotolarlo e ripetere gli stessi comandi in più blocchi:

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ "$A" -eq "0" ] && [ "$C" -eq "0" ]; then ... elif [ "$B" -ne "0" ] && [ "$C" -eq "0" ]; then ... fi 

Risposta

La sintassi di bash non è simile al C, anche se una piccola parte è ispirata da C. Non puoi semplicemente provare a scrivere codice C e aspettarti che funzioni.

Il punto principale di una shell è eseguire comandi. Il comando parentesi aperta [ è un comando che esegue un singolo test¹. Puoi anche scriverlo come test (senza la parentesi di chiusura finale). Gli operatori || e && sono operatori di shell, combinano comandi , non test.

Quindi, quando scrivi

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ] 

viene analizzato come

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ] 

che è uguale a

test [ "$A" -eq "0" || test "$B" -ne "0" ] && test "$C" -eq "0" 

Nota le parentesi non bilanciate? Sì, non va bene. Il tuo tentativo con le parentesi ha lo stesso problema: parentesi spurie.

La sintassi per raggruppare i comandi insieme è le parentesi graffe. Il modo in cui vengono analizzate le parentesi graffe richiede un comando completo prima di esse, quindi dovrai terminare il comando allinterno delle parentesi graffe con una nuova riga o un punto e virgola.

if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then … 

Lì “è un modo alternativo che consiste nellusare le doppie parentesi. A differenza delle singole parentesi, le doppie parentesi sono una sintassi speciale della shell. Delimitano espressioni condizionali . Allinterno delle doppie parentesi, puoi utilizzare parentesi e operatori come && e ||. Poiché le doppie parentesi sono sintassi della shell, la shell sa che quando questi operatori sono racchiusi tra parentesi, “fanno parte della sintassi dellespressione condizionale, non della sintassi ordinaria dei comandi della shell.

if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then … 

Se tutti i tuoi test sono numerici, esiste ancora un altro modo che delimita le espressioni artihmetiche . Le espressioni aritmetiche eseguono calcoli di interi con una sintassi molto simile al C.

if (((A == 0 || B != 0) && C == 0)); then … 

Potresti trovare la mia parentesi bash primer utile.

[ può essere usato in semplice sh. [[ e (( sono specifici per bash (e ksh e zsh).

¹ Può anche combina più test con operatori booleani, ma è complicato da usare e presenta sottili insidie, quindi non lo spiegherò.

Commenti

  • Grazie Giles. Questo vale per Bash 2 fino a Bash 4? Ho bisogno di qualcosa di leggermente trasportabile, ma Kusalananda ha detto che alcune cose che non facevo sono portatili (questo significa che quello che sto facendo è non portatile?). Qui, moderatamente significa da Bash 2 a Bash 4.
  • @jww [[ … ]] è stato aggiunto in bash 2.02. ((…)) è stato aggiunto in bash 2.0.
  • @Giles – grazie. Bash 2 è probabilmente ridicolo per molti. È dovuto alla nostra governance e alla nostra riluttanza di abbandonare le piattaforme più vecchie. Bash 2 e GCC 3 vengono visualizzati nei nostri test di Fedora 1. A volte lasceremo andare una piattaforma più vecchia, ma devono esserci delle ragioni. Non ' t sottoscrivere la politica di abbandono di Apple, Microsoft, Mozilla e così via.
  • @jww Tieni presente che la precedenza di || e && cambia da [ a [[ e ((. Uguale precedenza in [ (utilizza le parentesi per controllare lordine di valutazione), ma & & ha la precedenza maggiore in [[ e (( rispetto a || (come C).
  • @Roland No, parentesi allinterno di [[ … ]] o $((…)) servono solo per raggruppare.

Risposta

Utilizza [[:

if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ... 

Se preferisci [, funziona quanto segue:

if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ... 

Commenti

  • Grazie, Stephen. Nel mio caso, ho utilizzato il tuo primo esempio in questo modo … regex = ' ^ [0-9] + $ ' length = $ {#datearg} se! [[$ datearg = ~ $ regex & & $ length -eq 8]]; quindi echo " errore: non un numero di lenth di 8 "; fi

Risposta

Utilizza loperatore -o invece del tuo annidato ||. Puoi anche utilizzare -a per sostituire & & se necessario nelle altre istruzioni .

 EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true if [ "$A" -eq "0" -o "$B" -ne "0" ] && [ "$C" -eq "0" ]; then echo success;fi 

Commenti

  • Grazie. Mi sono imbattuto in -a e -o, ma non li ho sperimentati. Qualcuno su Stack Overflow ha detto di evitarlo. Sono perlopiù daccordo con loro poiché lo script è meno leggibile usandoli.
  • … ma più portabile.
  • @Kusalananda – Grazie per le avvertenze sulla portabilità. Lo script deve essere eseguito su sistemi da Bash 2 a Bash 4. [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]] avrà problemi su di essi?
  • Non ci saranno problemi finché continuerai a bash o qualsiasi altra shell che capisca [[ ... ]].
  • Il lato negativo dellutilizzo di -a è che non ' t cortocircuito se la prima espressione è falsa. Quindi, se ti affidi al cortocircuito per impedire lesecuzione di una seconda espressione potenzialmente fatale, non puoi usare -a. Esempio: pastebin.com/zM77TXW1

Lascia un commento

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