175

When I run commands in my shell as below, it returns an expr: non-integer argument error. Can someone please explain this to me?

$ x=20
$ y=5
$ expr x / y 
expr: non-integer argument
Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
Judking
  • 6,111
  • 11
  • 55
  • 84
  • 5
    @ShivanRaptor While one might argue that the question is an RTFM question, it is certainly a valid shell programming question. It is also a reasonable question for someone coming from languages that don't require dereferencing (e.g. Ruby or JavaScript). It should be left open. – Todd A. Jacobs Aug 07 '13 at 03:14
  • 6
    @ShivanRaptor No, this is on topic here. It's about programming in Bash. Unix/Linux is primarily for using the system, not programming. Now, shell scripting does span the boundary between programming and using the system, so this could be on topic on either site. If there were a question about "how do I set up networking", that would definitely belong on Unix/Linux. If it were a question about interactive keybindings in Bash, that would also belong there. But a question about shell scripting is definitely on topic here as well as there. – Brian Campbell Aug 07 '13 at 03:14
  • See my answer here, that illustrates subtraction and division of $BASH variables, using a call to Python from the shell (to convert int to float ...): https://stackoverflow.com/questions/8385627/subtract-two-variables-in-bash/55856163#55856163 – Victoria Stuart Apr 25 '19 at 19:22

6 Answers6

240

Those variables are shell variables. To expand them as parameters to another program (ie expr), you need to use the $ prefix:

expr $x / $y

The reason it complained is because it thought you were trying to operate on alphabetic characters (ie non-integer)

If you are using the Bash shell, you can achieve the same result using expression syntax:

echo $((x / y))

Or:

z=$((x / y))
echo $z
paddy
  • 60,864
  • 6
  • 61
  • 103
46

I believe it was already mentioned in other threads:

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

then you can simply type :

calc 7.5/3.2
  2.34375

In your case it will be:

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

or if you prefer, add this as a separate script and make it available in $PATH so you will always have it in your local shell:

#!/bin/bash
calc(){ awk "BEGIN { print $* }"; }
ktbiz
  • 586
  • 4
  • 13
zielonys
  • 461
  • 4
  • 4
26

Why not use let; I find it much easier. Here's an example you may find useful:

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

Another simple example - calculate number of days since 1970:

let days=$(date +%s)/86400
Mike Behr
  • 43
  • 4
18

Referencing Bash Variables Requires Parameter Expansion

The default shell on most Linux distributions is Bash. In Bash, variables must use a dollar sign prefix for parameter expansion. For example:

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

Of course, Bash also has arithmetic operators and a special arithmetic expansion syntax, so there's no need to invoke the expr binary as a separate process. You can let the shell do all the work like this:

x=20; y=5
echo $((x / y))
Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
  • 1
    See [Arithmetic Expansion](http://www.gnu.org/software/bash/manual/html_node/Arithmetic-Expansion.html#Arithmetic-Expansion) and [Shell Arithmetic](http://www.gnu.org/software/bash/manual/html_node/Shell-Arithmetic.html) in the Bash Reference Manual for all the gory details. – Todd A. Jacobs Aug 07 '13 at 03:26
  • 1
    This has nothing to do with _dereferencing_ but _interpolating_ and `expr` is discouraged in 2013. – Gilles Quénot Aug 07 '13 at 04:15
  • @sputnick You are clearly confused. Please feel free to consult a dictionary. See [dereference](https://www.google.com/search?q=define%3Adereference) and [interpolate](https://www.google.com/search?q=define%3Ainterpolate). – Todd A. Jacobs Aug 07 '13 at 04:25
  • I've heard ["interpolate"](http://unix.stackexchange.com/questions/13010/dollar-sign-interpolation-inside-quotes-in-bash) being used to refer to what others might call [parameter expansion](http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion). At first, I was going to say, keep dereferencing talk to C and C++ code, but no, they [say it in Bash world too](http://www.tldp.org/LDP/abs/html/complexfunct.html). So we're all talking about the same thing. +1 for the vote against `expr` though. – Prashant Kumar Aug 07 '13 at 04:37
  • 1
    A better word is _expanding_, but not _dereferencing_. _dereferencing_ is used when we use _pointers_, that's not the case here, that's just simple variables. – Gilles Quénot Aug 07 '13 at 04:40
  • 1
    @Prashant: tldp is not known to be a good reference in the bash world. – Gilles Quénot Aug 07 '13 at 04:44
7

To get the numbers after decimal point, you can do this:-

read num1 num2
div=`echo $num1 / $num2 | bc -l`
echo $div
Asclepius
  • 57,944
  • 17
  • 167
  • 143
1

let's suppose

x=50
y=5

then

z=$((x/y))

this will work properly . But if you want to use / operator in case statements than it can't resolve it. enter code here In that case use simple strings like div or devide or something else. See the code

taras
  • 6,566
  • 10
  • 39
  • 50
  • This is wrong. `/` works fine as a shell-case label. What doesn't work is to use `*` for multiply without quoting it, which might be what you actually did; _that_ causes it to effectively override all following items in the case, which in your example is 'devide' and 'modulo' – dave_thompson_085 Apr 25 '20 at 06:11