282

I have the script below to subtract the counts of files between two directories but the COUNT= expression does not work. What is the correct syntax?

#!/usr/bin/env bash FIRSTV=`ls -1 | wc -l` cd .. SECONDV=`ls -1 | wc -l` COUNT=expr $FIRSTV-$SECONDV ## -> gives 'command not found' error echo $COUNT 
1

9 Answers 9

466

Try this Bash syntax instead of trying to use an external program expr:

count=$((FIRSTV-SECONDV)) 

BTW, the correct syntax of using expr is:

count=$(expr $FIRSTV - $SECONDV) 

But keep in mind using expr is going to be slower than the internal Bash syntax I provided above.

Sign up to request clarification or add additional context in comments.

7 Comments

This form is magnitudes quicker than using the expr external program.
Thanks. Backtick is old shell syntax. BASH supports new $(command) syntax for command substitution. Also since BASH support arithmetic operations in $(( ... )) it is better to not to use an external utility expr
I never new you could reference variables without the "$", very interesting. This works on Ubuntu 12,14 just FYI.
@AlikElzin-kilaka: In bash $(( ... )) is use for evaluating arithmetic expressions.
Note that $(( is not a bashism. It works in dash, and is in POSIX. Moreover, shellcheck will complain if you use expr: shellcheck.net/wiki/SC2003
|
254

You just need a little extra whitespace around the minus sign, and backticks:

COUNT=`expr $FIRSTV - $SECONDV` 

Be aware of the exit status:

The exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null or 0.

Keep this in mind when using the expression in a bash script in combination with set -e which will exit immediately if a command exits with a non-zero status.

3 Comments

This answer also works in posix sh shell. For portability, you may want to use this answer.
It's worth noting that according to Shellcheck, expr is a codesmell due to it being antiquated and difficult to use: github.com/koalaman/shellcheck/wiki/SC2003
I concur; Anubhava's answer should be the accepted one. expr only makes sense if you need compatibility back to the dark ages when Solaris sh was popular and HP-UX and AIX were still a thing. POSIX sh too has supported arithmetic expressions for many years now.
32

You can use:

((count = FIRSTV - SECONDV)) 

to avoid invoking a separate process, as per the following transcript:

pax:~$ FIRSTV=7 pax:~$ SECONDV=2 pax:~$ ((count = FIRSTV - SECONDV)) pax:~$ echo $count 5 

Comments

18

This is how I always do maths in Bash:

count=$(echo "$FIRSTV - $SECONDV"|bc) echo $count 

3 Comments

that's only necessary if you're dealing with floating point numbers.
I realise that, but I'd rather make a habit of catching those cases with a |bc type command than miss it once or twice. Different strokes for different folks as they say.
@glenn jackman but that's what I was searching without even knowing my decimals math were "floating point numbers". No other answer worked for me except this!
13

White space is important, expr expects its operands and operators as separate arguments. You also have to capture the output. Like this:

COUNT=$(expr $FIRSTV - $SECONDV) 

but it's more common to use the builtin arithmetic expansion:

COUNT=$((FIRSTV - SECONDV)) 

Comments

9

For simple integer arithmetic, you can also use the builtin let command.

 ONE=1 TWO=2 let "THREE = $ONE + $TWO" echo $THREE 3 

For more info on let, look here.

2 Comments

@another.anon.coward Your link's better than mine +1. (... and stealing link)
Had a lot of trouble in getting this working. Finally this worked - let "sanity_check_duration=sanity_check_duration_end_time_delay_sec - sanity_check_duration_start_time_delay_sec" (removing dollar sign from variables)
2

Alternatively to the suggested 3 methods you can try let which carries out arithmetic operations on variables as follows:

let COUNT=$FIRSTV-$SECONDV

or

let COUNT=FIRSTV-SECONDV

Comments

0

Diff Real Positive Numbers

diff_real () { echo "df=($1 - $2); if (df < 0) { df=df* -1}; print df" | bc -l; } 

Usage

var_a=10 var_b=4 output=$(diff_real $var_a $var_b) # 6 ######### var_a=4 var_b=10 output=$(diff_real $var_a $var_b) # 6 

Comments

-1

Use BASH:

#!/bin/bash # home/victoria/test.sh START=$(date +"%s") ## seconds since Epoch for i in $(seq 1 10) do sleep 1.5 END=$(date +"%s") ## integer TIME=$((END - START)) ## integer AVG_TIME=$(python -c "print(float($TIME/$i))") ## int to float printf 'i: %i | elapsed time: %0.1f sec | avg. time: %0.3f\n' $i $TIME $AVG_TIME ((i++)) ## increment $i done 

Output

$ ./test.sh i: 1 | elapsed time: 1.0 sec | avg. time: 1.000 i: 2 | elapsed time: 3.0 sec | avg. time: 1.500 i: 3 | elapsed time: 5.0 sec | avg. time: 1.667 i: 4 | elapsed time: 6.0 sec | avg. time: 1.500 i: 5 | elapsed time: 8.0 sec | avg. time: 1.600 i: 6 | elapsed time: 9.0 sec | avg. time: 1.500 i: 7 | elapsed time: 11.0 sec | avg. time: 1.571 i: 8 | elapsed time: 12.0 sec | avg. time: 1.500 i: 9 | elapsed time: 14.0 sec | avg. time: 1.556 i: 10 | elapsed time: 15.0 sec | avg. time: 1.500 $ 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.