I have d1="11" and d2="07". I want to convert d1 and d2 to integers and perform d1-d2. How do I do this in UNIX?
d1 - d2 currently returns "11-07" as result for me.
I have d1="11" and d2="07". I want to convert d1 and d2 to integers and perform d1-d2. How do I do this in UNIX?
d1 - d2 currently returns "11-07" as result for me.
The standard solution:
expr $d1 - $d2
You can also do:
echo $(( d1 - d2 ))
but beware that this will treat 07 as an octal number! (so 07 is the same as 7, but 010 is different than 10).
echo $((d1-10#$d2)) Beware: it is not the same than echo $((d1-10#d2))nounset and errexit (which you should always use). I have written many tests for different scenarios in my answer stackoverflow.com/a/59781257/117471nounset is often a good idea. But you should never use errexit.Any of these will work from the shell command line. bc is probably your most straight forward solution though.
Using bc:
$ echo "$d1 - $d2" | bc
Using awk:
$ echo $d1 $d2 | awk '{print $1 - $2}'
Using perl:
$ perl -E "say $d1 - $d2"
Using Python:
$ python -c "print $d1 - $d2"
all return
4
expr, awk, bc, and dc, but all of those tools handle the case d1=09 by treating 09 as the decimal value 9. However, perl and python treat it as a syntax error. You get different results for the case d1=010echo $((d1-10#$d2))The title of the question leads people here, so I decided to answer that question for everyone else since the OP's described case was so limited.
I finally settled on writing a function.
0 in case of non-int:int(){ printf '%d' ${1:-} 2>/dev/null || :; }
int(){ expr 0 + ${1:-} 2>/dev/null||:; }
int(){ expr ${1:-} : '[^0-9]*\([0-9]*\)' 2>/dev/null||:; }
# This is a combination of numbers 1 and 2
int(){ expr ${1:-} : '[^0-9]*\([0-9]*\)' 2>/dev/null||:; }
If you want to get a non-zero status code on non-int, remove the ||: (aka or true) but leave the ;
# Wrapped in parens to call a subprocess and not `set` options in the main bash process
# In other words, you can literally copy-paste this code block into your shell to test
( set -eu;
tests=( 4 "5" "6foo" "bar7" "foo8.9bar" "baz" " " "" )
test(){ echo; type int; for test in "${tests[@]}"; do echo "got '$(int $test)' from '$test'"; done; echo "got '$(int)' with no argument"; }
int(){ printf '%d' ${1:-} 2>/dev/null||:; };
test
int(){ expr 0 + ${1:-} 2>/dev/null||:; }
test
int(){ expr ${1:-} : '[^0-9]*\([0-9]*\)' 2>/dev/null||:; }
test
int(){ printf '%d' $(expr ${1:-} : '[^0-9]*\([0-9]*\)' 2>/dev/null)||:; }
test
# unexpected inconsistent results from `bc`
int(){ bc<<<"${1:-}" 2>/dev/null||:; }
test
)
int is a function
int ()
{
printf '%d' ${1:-} 2> /dev/null || :
}
got '4' from '4'
got '5' from '5'
got '0' from '6foo'
got '0' from 'bar7'
got '0' from 'foo8.9bar'
got '0' from 'baz'
got '0' from ' '
got '0' from ''
got '0' with no argument
int is a function
int ()
{
expr 0 + ${1:-} 2> /dev/null || :
}
got '4' from '4'
got '5' from '5'
got '' from '6foo'
got '' from 'bar7'
got '' from 'foo8.9bar'
got '' from 'baz'
got '' from ' '
got '' from ''
got '' with no argument
int is a function
int ()
{
expr ${1:-} : '[^0-9]*\([0-9]*\)' 2> /dev/null || :
}
got '4' from '4'
got '5' from '5'
got '6' from '6foo'
got '7' from 'bar7'
got '8' from 'foo8.9bar'
got '' from 'baz'
got '' from ' '
got '' from ''
got '' with no argument
int is a function
int ()
{
printf '%d' $(expr ${1:-} : '[^0-9]*\([0-9]*\)' 2>/dev/null) || :
}
got '4' from '4'
got '5' from '5'
got '6' from '6foo'
got '7' from 'bar7'
got '8' from 'foo8.9bar'
got '0' from 'baz'
got '0' from ' '
got '0' from ''
got '0' with no argument
int is a function
int ()
{
bc <<< "${1:-}" 2> /dev/null || :
}
got '4' from '4'
got '5' from '5'
got '' from '6foo'
got '0' from 'bar7'
got '' from 'foo8.9bar'
got '0' from 'baz'
got '' from ' '
got '' from ''
got '' with no argument
I got sent down this rabbit hole because the accepted answer is not compatible with set -o nounset (aka set -u)
# This works
$ ( number="3"; string="foo"; echo $((number)) $((string)); )
3 0
# This doesn't
$ ( set -u; number="3"; string="foo"; echo $((number)) $((string)); )
-bash: foo: unbound variable
let d=d1-d2;echo $d;
This should help.
d=$(( d1 - d2 )); echo "$d", as covered by the accepted answer (with the same caveat that 0-prefixed numbers are interpreted as octals).Use this:
#include <stdlib.h>
#include <string.h>
int main()
{
const char *d1 = "11";
int d1int = atoi(d1);
printf("d1 = %d\n", d1);
return 0;
}
etc.