Intero a confronto: espressione aritmetica o espressione condizionale


20

In Bash, due numeri interi possono essere confrontati usando l'espressione condizionale

arg1 OP arg2

OP è uno -eq, -ne, -lt, -le, -gt, o -ge. Questi operatori binari aritmetici restituiscono vero se arg1 è uguale, non uguale a, minore di, minore o uguale a, maggiore di, o maggiore di o uguale a arg2 , rispettivamente. Arg1 e arg2 possono essere numeri interi positivi o negativi.

o espressione aritmetica:

<= >= < > confronto

== != uguaglianza e disuguaglianza

Perché abbiamo due modi diversi per confrontare due numeri interi? Quando usare quale?

Ad esempio, [[ 3 -lt 2 ]]utilizza l'espressione condizionale e (( 3 < 2 ))utilizza l'espressione aritmetica. Entrambi restituiscono 0 quando il confronto è vero

Quando si confrontano due numeri interi, questi due metodi possono sempre essere usati in modo intercambiabile? Se sì, perché Bash ha due metodi anziché uno?


1
= != < <= > >=confrontare le stringhe . 1 -eq 01ma 1 != 01e 8 -lt 42ma8 > 42
dave_thompson_085,

Sono sovraccarichi di espressioni aritmetiche.
Tim

1
dovrai cercare nei log delle modifiche di base per scoprire quando ogni funzione è stata aggiunta. Sospetto che le espressioni aritmetiche siano state aggiunte molto più tardi del comando test.
Glenn Jackman,

Non sto chiedendo di confrontare le stringhe. @muru.
Tim

Risposte:


28

Sì, abbiamo due modi diversi di confrontare due numeri interi.

Sembra che questi fatti non siano ampiamente accettati in questo forum:

  1. All'interno del linguaggio [ ]degli operatori per il confronto l'aritmetica sono -eq, -ne, -lt, -le, -gte -ge.

    Poiché sono anche all'interno di un comando di prova e all'interno di un [[ ]].

    Sì dentro questo idiomi, =, <, ecc, sono operatori di stringa.

  2. All'interno del linguaggio (( ))degli operatori per il confronto l'aritmetica sono ==, !=, <, <=, >, e >=.

    No, questa non è una "espansione aritmetica" (che inizia con a $) come $(( )). È definito come un "Comando composto" in man bash.

    Sì, segue le stesse regole (internamente) dell'espansione "aritmetica" ma non ha output, ma solo un valore di uscita. Potrebbe essere usato in questo modo:

if (( 2 > 1 )); then ...

Perché abbiamo due modi diversi per confrontare due numeri interi?

Immagino che quest'ultimo sia (( ))stato sviluppato come un modo più semplice per eseguire test aritmetici. È quasi uguale al $(( ))ma non ha output.

Perché due? Beh, lo stesso che il motivo per cui abbiamo due printf(esterno e internamente) o quattro di prova (esterno test, integrato test, [e [[). È così che crescono le conchiglie, migliorando un'area in un anno, migliorandone un'altra l'anno successivo.

Quando usare quale?

Questa è una domanda molto difficile perché non ci dovrebbero essere differenze effettive. Naturalmente ci sono alcune differenze nel modo in cui [ ]un'opera e (( ))un'opera internamente, ma: quale è meglio confrontare due numeri interi? Qualcuno !.

Quando si confrontano due numeri interi, questi due metodi possono sempre essere usati in modo intercambiabile?

Per due numeri sono costretto a dire di sì.
Ma per variabili, espansioni, operazioni matematiche potrebbero esserci differenze chiave che dovrebbero favorire l'una o l'altra. Non posso dire che assolutamente entrambi sono uguali. Per uno, (( ))potrebbero eseguire diverse operazioni matematiche in sequenza:

if (( a=1, b=2, c=a+b*b )); then echo "$c"; fi

Se sì, perché Bash ha due metodi anziché uno?

Se entrambi sono utili, perché no ?.


1
=è un compito ed ==è un confronto nelle espansioni aritmetiche. La domanda lo cita correttamente. Ma la risposta è sbagliata
ceving

12

Storicamente, il testcomando è esistito per primo (almeno fino alla Unix Seventh Edition nel 1979). Ha usato gli operatori =e !=per confrontare le stringhe, e -eq, -ne, -lt, ecc per confrontare i numeri. Ad esempio, test 0 = 00è falso, ma test 0 -eq 00è vero. Non so perché sia ​​stata scelta questa sintassi, ma potrebbe essere stato per evitare di usare <e >, che la shell avrebbe analizzato come operatori di reindirizzamento. Il testcomando ha ottenuto un'altra sintassi qualche anno dopo: [ … ]è equivalente a test ….

La [[ … ]]sintassi condizionale, all'interno della quale <e >può essere utilizzata come operatore senza virgolette, è stata aggiunta in seguito, in ksh. Ha mantenuto la retrocompatibilità con [ … ], quindi ha usato gli stessi operatori, ma ha aggiunto <e >confrontato le stringhe (ad esempio, [[ 9 > 10 ]]ma [[ 9 -lt 10 ]]). Per ulteriori informazioni, consultare l' utilizzo della parentesi singola o doppia - bash

Le espressioni aritmetiche arrivarono anche più tardi del testcomando, nella shell Korn , in qualche momento degli anni '80. Seguirono la sintassi del linguaggio C, che era molto popolare nei circoli Unix. Quindi hanno usato gli operatori di C: ==per uguaglianza, <=per meno o uguale, ecc.

Unix Seventh Edition non aveva espressioni aritmetiche, ma aveva il exprcomando , che implementava anche una sintassi simil-C per operazioni su numeri interi, inclusi i suoi operatori di confronto. In uno script di shell, i personaggi <e >dovevano essere citati per proteggerli dalla shell, ad esempio if expr 1 \< 2; …è equivalente a if test 1 -lt 2; …. L'aggiunta di espressioni aritmetiche alla shell ha reso la maggior parte degli usi exprobsoleti, quindi non è noto oggi.

In uno script sh, generalmente useresti espressioni aritmetiche per calcolare un valore intero e [ … ]per confrontare numeri interi.

if [ "$((x + y))" -lt "$z" ]; then 

In uno script ksh, bash o zsh, puoi usare ((…))entrambi.

if ((x + y < z)); then 

Il [[ … ]]modulo è utile se si desidera utilizzare condizionali che coinvolgono cose diverse dagli interi.


1

Secondo la pagina man di test, = e! = Sono usati per i confronti delle stringhe mentre le espressioni -eq, -gt, -lt, -ge, -le e -ne sono confronti interi. Ho sempre seguito questa convenzione quando scrivevo script di shell e funziona sempre. Tenere presente che se si hanno variabili nell'espressione, potrebbe essere necessario citare le variabili in qualche modo per evitare di fare un confronto nullo.

Sulla carta, facciamo confronti tra stringhe / numeri senza pensarci troppo. Un computer d'altra parte non sa se 987 è un numero o una stringa di caratteri. Hai bisogno dei diversi operatori per dire al computer cosa fare in modo da ottenere il risultato giusto. Ci sono alcune informazioni aggiuntive qui che spiegano parte della storia. In sostanza, le variabili non sono tipizzate e sono rimaste così per la compatibilità storica.


Nel mio post, = e !=sono operatori aritmetici, mentre la manpage di testmostra solo operatori di espressioni condizionali.
Tim
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.