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.
5 Answers
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).
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 3An answer that is not limited to the OP's case
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.
TL;DR
I finally settled on writing a function.
- If you want
0in case of non-int:
int(){ printf '%d' ${1:-} 2>/dev/null || :; } - If you want [empty_string] in case of non-int:
int(){ expr 0 + ${1:-} 2>/dev/null||:; } - If you want find the first int or [empty_string]:
int(){ expr ${1:-} : '[^0-9]*\([0-9]*\)' 2>/dev/null||:; } - If you want find the first int or 0:
# 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 ;
Tests
# 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 ) Test output
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 Note
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.
1Use 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.
1