I am trying to call the function "warn" if the calculation is TRUE. I am still not quite comfortable with the syntax, would like some tips on how to fix the last line.
if [ "$noproc" -gt 0 ]; then
echo "WARNING: NoProc at $noproc for $process processes." >> $log
elif [ "$max" -ge 11 ]; then
[ $(($max - $total)) -lt 6 && [ $idle -le $(($max \* 0.25 | bc -l)) ] ] | warn $total $process $max $idle
The error I get: line 97: [: missing ` ] '
If your tagging for this question is correct and you're genuinely using bash (which is to say that your script starts with #!/bin/bash
, or if not started via a shebang you use bash yourscript
rather than sh yourscript
), you might as well take advantage of it.
# extended bash math syntax
if (( (max - total) < 6 )) && (( idle <= (max / 4) )); then
warn "$total" "$process" "$max" "$idle"
fi
If, for whatever reason, you don't want to use (( ))
, you can still use [[ ]]
, which gives you a test context with its own extended syntax:
# extended bash test syntax
if [[ $((max - total)) -lt 6 && $idle -le $(bc -l <<<"$max*0.25") ]]; then
warn "$total" "$process" "$max" "$idle"
fi
...whereas if you want to be compatible with POSIX sh, you need to end the test before you can put in a shell-level logical-AND operator.
# corrected POSIX-compliant test syntax
if [ "$((max - total))" -lt 6 ] && [ "$idle" -le "$(bc -l <<<"$max*0.25")" ]; then
warn "$total" "$process" "$max" "$idle"
fi
To understand why, let's look at how your original command would parse, if you changed the (utterly incorrect) |
symbol to &&
instead:
# Equivalent (longer form) of the original code, with pipe corrected to logical-AND
if [ $(($max - $total)) -lt 6; then
if [ $idle -le $(($max \* 0.25 | bc -l)) ] ]; then
warn $total $process $max $idle
fi
fi
Note that this is running, as a single command, [ $(($max - $total)) -lt 6
.
[
is not special shell syntax -- it's just a command. In older shells it was actually /usr/bin/[
; today, there's also a [
builtin as well, but other than being faster to execute, it behaves exactly the same way as it would have were it executing the old, external command.
That [
command expects to be passed a ]
as its last argument, since there's no ]
after the -lt 6
, you get a syntax error and it exits.
Similarly, your code would then (if the first command succeeded) run [ $idle -le $(($max \* 0.25 | bc -l)) ] ]
. Here, you have a [
command passed two ]
s on the end; it simply doesn't know what to do with the second one.
- You can't nest
[
invocations. Even if you could, a && (b) === a && b
in logic.
- You can't use commands in arithmetic expansions.
- Bash's
[[
is safer than [
.
- Use More Quotes™.
Result:
[[ "$(($max - $total))" -lt 6 ]] && [[ "$idle" -le "$(bc -l <<< "$max * 0.25")" ]] | warn "$total $process $max $idle"