Comment puis-je faire une division avec des variables dans un shell Linux?

136

Lorsque j'exécute des commandes dans mon shell comme ci-dessous, cela renvoie une expr: non-integer argumenterreur. Quelqu'un pourrait-il me l'expliquer?

$ x=20
$ y=5
$ expr x / y 
expr: non-integer argument
Juger
la source
4
@ShivanRaptor Bien que l'on puisse affirmer que la question est une question RTFM, c'est certainement une question de programmation shell valide. C'est aussi une question raisonnable pour quelqu'un venant de langages qui ne nécessitent pas de déréférencement (par exemple Ruby ou JavaScript). Il devrait être laissé ouvert.
Todd A. Jacobs
6
@ShivanRaptor Non, c'est sur le sujet ici. Il s'agit de programmer dans Bash. Unix / Linux sert principalement à utiliser le système, pas à programmer. Maintenant, les scripts shell couvrent la frontière entre la programmation et l'utilisation du système, donc cela pourrait être sur le sujet sur l'un ou l'autre site. S'il y avait une question sur "comment configurer le réseau", cela appartiendrait certainement à Unix / Linux. S'il s'agissait d'une question sur les raccourcis clavier interactifs dans Bash, cela y ferait également partie. Mais une question sur les scripts shell est définitivement sur le sujet ici et là.
Brian Campbell
Voir ma réponse ici, qui illustre la soustraction et la division des variables $ BASH, en utilisant un appel à Python depuis le shell (pour convertir int en float ...): stackoverflow.com/questions/8385627/…
Victoria Stuart

Réponses:

195

Ces variables sont des variables shell. Pour les étendre en tant que paramètres à un autre programme ( c'est-à-dire expr ), vous devez utiliser le $préfixe:

expr $x / $y

La raison pour laquelle il s'est plaint est parce qu'il pensait que vous essayiez d'opérer sur des caractères alphabétiques ( c'est -à- dire non entiers)

Si vous utilisez le shell Bash, vous pouvez obtenir le même résultat en utilisant la syntaxe d'expression:

echo $((x / y))

Ou:

z=$((x / y))
echo $z
paddy
la source
1
Vous pouvez en savoir beaucoup en lisant la page de manuel de bash. Tapez man bashà l'invite ( qpour quitter)
paddy
62
Il faut noter quelque part sur cette page que la plupart des shells GNU / Linux (sinon tous) n'effectuent que des opérations sur des entiers .
Skippy le Grand Gourou
35

Je crois que cela a déjà été mentionné dans d'autres fils:

calc(){ awk "BEGIN { print "$*" }"; }

alors vous pouvez simplement taper:

calc 7.5/3.2
  2.34375

Dans votre cas, ce sera:

x=20; y=3;
calc $x/$y

ou si vous préférez, ajoutez ceci en tant que script séparé et rendez-le disponible dans $ PATH afin que vous l'ayez toujours dans votre shell local:

#!/bin/bash
calc(){ awk "BEGIN { print $* }"; }
Zielonys
la source
4
Vous pouvez également utiliserecho '1 / 3' | bc -l
Eugene
19

Pourquoi ne pas utiliser let; Je trouve cela beaucoup plus facile. Voici un exemple que vous pourriez trouver utile:

start=`date +%s`
# ... do something that takes a while ...
sleep 71

end=`date +%s`
let deltatime=end-start
let hours=deltatime/3600
let minutes=(deltatime/60)%60
let seconds=deltatime%60
printf "Time spent: %d:%02d:%02d\n" $hours $minutes $seconds

Un autre exemple simple - calculer le nombre de jours depuis 1970:

let days=$(date +%s)/86400
Mike Behr
la source
15

Le référencement des variables Bash nécessite une extension des paramètres

Le shell par défaut sur la plupart des distributions Linux est Bash. Dans Bash, les variables doivent utiliser un préfixe de signe dollar pour l' expansion des paramètres . Par exemple:

x=20
y=5
expr $x / $y

Bien sûr, Bash a également des opérateurs arithmétiques et une syntaxe d'expansion arithmétique spéciale , il n'est donc pas nécessaire d'invoquer le binaire expr comme un processus séparé. Vous pouvez laisser le shell faire tout le travail comme ceci:

x=20; y=5
echo $((x / y))
Todd A. Jacobs
la source
Voir Expansion arithmétique et arithmétique de shell dans le manuel de référence de Bash pour tous les détails sanglants.
Todd A. Jacobs
1
Cela n'a rien à voir avec le déréférencement mais l' interpolation et exprest déconseillé en 2013.
Gilles Quenot
@sputnick Vous êtes clairement confus. N'hésitez pas à consulter un dictionnaire. Voir déréférencer et interpoler .
Todd A. Jacobs
1
Un meilleur mot se développe , mais pas de déréférencement . le déréférencement est utilisé lorsque nous utilisons des pointeurs , ce n'est pas le cas ici, ce sont juste des variables simples.
Gilles Quenot
1
@Prashant: tldp n'est pas connu pour être une bonne référence dans le monde bash.
Gilles Quenot
1

Supposons

x=50
y=5

puis

z=$((x/y))

cela fonctionnera correctement. Mais si vous souhaitez utiliser / operator dans les instructions case, il ne peut pas le résoudre. entrez le code ici Dans ce cas, utilisez des chaînes simples comme div ou devide ou autre chose. Voir le code

Pooja Rajput
la source
C'est faux. /fonctionne bien comme une étiquette de coque. Ce qui ne fonctionne pas, c'est d'utiliser *pour multiplier sans le citer, ce qui pourrait être ce que vous avez réellement fait; qui l' amène à remplacer efficacement tous les éléments suivants dans le cas, qui dans votre exemple est 'devide' et 'modulo'
dave_thompson_085
0

Pour obtenir les nombres après la virgule décimale, vous pouvez faire ceci: -

read num1 num2
div=`echo $num1 / $num2 |bc -l`
echo $div
Shayan Chatterjee
la source