N_RESULTS=$( echo "($DECI - 1) / 10 + 1" | bc -l )
What let
does
Consider:
let "N_RESULTS = ($DECI - 1) / 10 + 1" | bc -l
This pipeline has two parts. The first is the shell's let
command. Because of the |
symbol, output from the let
command is passed to stdin of the bc
command. While 'let
is capable of performing integer arithmetic and can assign values to variable, it does not produce any output. Hence, even if it ran correctly, it would pass nothing to bc
.
Here is an example of a working let
command:
$ let "result = (123 - 1) / 10 + 1"
$ echo $result
13
If, however, we were to supply a floating point argument, an error would result:
$ let "result = (123.0 - 1) / 10 + 1"
bash: let: result = (123.0 - 1) / 10 + 1: syntax error: invalid arithmetic operator (error token is ".0 - 1) / 10 + 1")
The let
command, like the rest of the shell, only does integer arithmetic.
What bc
does
bc
does floating point arithmetic and can be used to assign and manipulate variables:
$ echo "result = (123.0123 - 1) / 10 + 1; print result" | bc -l
13.20123000000000000000
Note, however, that the above does not, by itself create any shell-usable variables. The definition of result
expires when the bc
finishes processing. In order to pass the value back to the shell, we need to do a shell variable assignment such as:
$ result=$(echo "(123.0123 - 1) / 10 + 1" | bc -l )
$ echo $result
13.20123000000000000000
The $(...)
construct is called command substitution. It runs a command, in this case the echo and bc pipeline, and puts its stdout on the command line where it is assigned to the variable result
.
As a side note, it usually considered best practices to use lower-case names for your shell variables. The system's shell variables are all upper-case and you don't want to accidentally overwrite one of them.
What is the bc
equivalent for [[ $offset -lt $result ]]
The shell test
commands, including [
and [[
, produce a useful exit code that can be used in if
, while
, and other contexts, such as &&
and ||
, where exit codes are used to determine program flow. bc
does not emulate that behavior. It returns an exit code of 0
for any successful calculation. It returns non-zero exit codes if an error occurred. The examples below show how, with the help of grep
, bc
can be used to set useful exit codes.
In GNU bc
, relational expressions evaluate to 1
for true and 0
for false. So, to test whether offset
is less than result
, we just check whether bc
returns 0
or 1
. Here, grep
is used to examine the output from bc
and set an appropriate return code that can be used in if
, while
, or other places where the shell would test for a return code. For example:
$ offset=1.25; result=1.33
$ echo "$offset < $result" | bc -l | grep -q 1 && echo yes || echo no
yes
$ offset=1.35
$ echo "$offset < $result" | bc -l | grep -q 1 && echo yes || echo no
no
Under non-GNU bc
, the same thing can be done but a formal if
statement is required:
echo "if ($offset < $result) print 1 else print 0 " | bc -l | grep -q 1 && echo yes || echo no