Argomento stringa su intero in bash


74

Cercando di capire come convertire un argomento in un numero intero per eseguire l'aritmetica e quindi stamparlo, dire per addOne.sh:

echo $1 + 1
>>sh addOne.sh 1
prints 1 + 1

Cerco di formattare la tua domanda, ma rimane in qualche modo poco chiara. printf "1 + %s\n" $1 won't do ?
Archemar,

Risposte:


89

In bash, non si "converte un argomento in un numero intero per eseguire l'aritmetica". In bash, le variabili sono trattate come numeri interi o stringhe a seconda del contesto.

Per eseguire l'aritmetica, è necessario richiamare l'operatore di espansione aritmetica $((...)). Per esempio:

$ a=2
$ echo "$a + 1"
2 + 1
$ echo "$(($a + 1))"
3

o generalmente preferito:

$ echo "$((a + 1))"
3

Dovresti essere consapevole che bash (al contrario di ksh93, zsh o yash) esegue solo l' aritmetica dei numeri interi . Se hai numeri in virgola mobile (numeri con decimali), allora ci sono altri strumenti per aiutarti. Ad esempio, utilizzare bc:

$ b=3.14
$ echo "$(($b + 1))"
bash: 3.14 + 1: syntax error: invalid arithmetic operator (error token is ".14 + 1")
$ echo "$b + 1" | bc -l
4.14

Oppure puoi usare una shell con supporto aritmetico in virgola mobile invece di bash:

zsh> echo $((3.14 + 1))
4.14

L'uso di $ (()) o (()) non è sicuro se non si conoscono le stringhe (come l'input dell'utente). Considera questo: foo = foo ((foo + = 0)) Questo si bloccherà lo script mentre cerca di valutare ricorsivamente foo. Lo stesso con: foo = foo foo = $ ((foo + 0))
art

12

In altro modo, puoi usare expr

Ex:

$ version="0002"
$ expr $version + 0
2
$ expr $version + 1
3

10

In bash, puoi eseguire la conversione da qualsiasi cosa in intero usando printf -v :

printf -v int '%d\n' "$1" 2>/dev/null

Il numero fluttuante verrà convertito in intero, mentre qualsiasi cosa non assomiglierà a un numero verrà convertito in 0. L'esponenziazione verrà troncata al numero prima e

Esempio:

$ printf -v int '%d\n' 123.123 2>/dev/null
$ printf '%d\n' "$int"
123
$ printf -v int '%d\n' abc 2>/dev/null
$ printf '%d\n' "$int"
0
$ printf -v int '%d\n' 1e10 2>/dev/null
$ printf '%d\n' "$int"
1

2
In altre shell senza printf -vquesto si può ottenere con la sostituzione del comando:int="$(printf '%d' 123.123 2>/dev/null)"
Adrian Günter,

2
Questo non funziona in bash.
Michael Martinez, il

@MichaelMartinez sei sicuro? Qual è la versione di bashte utilizzata?
cuonglm

GNU bash, versione 4.2.46 (1) -release (x86_64-redhat-linux-gnu)
Michael Martinez,

5

Una situazione simile si è verificata di recente durante lo sviluppo di script bash da eseguire in ambienti Linux e OSX. Il risultato di un comando in OSX ha restituito una stringa contenente il codice risultato; Per esempio, " 0". Naturalmente, questo non è riuscito a testare correttamente nel seguente caso:

if [[ $targetCnt != 0 ]]; then...

La soluzione era quella di forzare (cioè "convertire") il risultato in un numero intero, simile a quello che ha risposto @ John1024 in modo che funzioni come previsto:

targetCnt=$(($targetCnt + 0))
if [[ $targetCnt != 0 ]]; then...

3
==ecc. in [[(anche [noto test) fare il confronto delle stringhe. Esistono diversi operatori per il confronto aritmetico, ad esempio [[ $targetcnt -ne 0 ]]; vedere la pagina man (o informazioni) in Espressioni condizionali. Per tagliare gli spazi in modo specifico, è possibile utilizzare l' [espansione variabile non quotata [ $targetcnt == 0 ]per ottenere il wordplitting predefinito (NON eseguito in [[), ma in generale tale approccio ti mette in pericolo.
dave_thompson_085,

-2

attenzione ai codici colore, anche se in trace ( -x) non appariranno, ciò che lo darebbe è che la stringa che dovrebbe essere un numero è racchiusa tra virgolette, non importa come lo stampi.


1
Votato verso il basso, poiché trovo la tua risposta un po 'poco chiara. Forse potresti aggiungere a cosa dovrebbe essere corretto lo script?
Time4Tea

questa è stata la risposta migliore nella ricerca di bash + intero + stringa, quindi ho aggiunto un'informazione relativa ad essa che non è stata inclusa tra le risposte, cioè quando le stringhe sono avvolte in codici colori potrebbe non essere chiaro il motivo per cui operazioni come $((var+var))falliscono anche sebbene se tu echoo printfentrambi tu sia uguale. Non conosco la correzione poiché sono stato in grado di risolverlo solo disabilitando i codici colore alla fonte dell'output. Per individuarlo nei log di traccia vedrai la variabile offensiva assegnata come var='0'dovrebbe essere semplicementevar=0
untore

Quello che puoi fare è assicurarti che l'output non abbia codici colore con sedse non puoi disabilitarlo
untore
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.