Bash: Features of Arithmetic Operations - Increment ((expression++))
Greetings!

When testing the host availability check script I mentioned last time, I encountered an interesting Bash feature when performing arithmetic operations💪.

👨💻What is the point: My script uses the check_count variable, which contains the current number of failed checks. This counter is increased with the increment command: ((check_count++)). The key word here is command. For further understanding, it is worth adding a bit of context😒

🤯Context: In Bash, the ((expression)) syntax performs two functions:

  1. Arithmetic evaluation.
  2. Logical check of the result (return code, also known as return code, rc).

Return code features of arithmetic operations:

And an operation of the form ((expression++)) first returns the current value of the variable, and then increments it🍿

So, if the initial value is check_count=0, then on the first execution of the ((check_count++)) command, Bash first returns code 1, which is interpreted as an error😵💫

By default, Bash ignores any errors and continues execution. Therefore, in my scripts I often use the shell option set -e so that the script exits on any error - this makes its behavior more predictable. And it seems obvious: got an error - exited, but the script has asynchronous tasks (&) running in subprocesses🤔

Example from the check_hosts.sh script:

BASH
for host in "${CHECK_HOSTS[@]}"; do
    monitor_host "$host" &
done
Click to expand and view more

This block launches monitor_host in parallel for each host from the specified list. If a subprocess entered the else branch and reached ((check_count++)), where check_count was equal to 0, it exited with an error because of set -e. At the same time, the main script and other subprocesses continued working💪

This led to non-obvious behavior: some processes exited, while others continued running. Without detailed checks, you might not notice it. To catch this moment, I had to strain my brain a little🤯

👌Solution: I added a logical “or” || true so that the command always exits successfully:

BASH
((check_count++)) || true
Click to expand and view more

Another possible (and probably more correct) way is to use the prefix form:

BASH
((++check_count))
Click to expand and view more

In this case, Bash immediately returns the new value, and if it is greater than 0 (which it will be), the return code is 0.

Or, as I was told, explicitly add one:

BASH
check_count=$((check_count+1))
Click to expand and view more

I knew about this nuance in Bash arithmetic, but this was the first time I encountered it in the context of asynchronous commands.

Copyright Notice

Author: Ivan Cherniy

Link: https://r4ven.me/en/automation/bash-osobennosti-arifmeticheskih-operaczij-inkrement-expression/

License: CC BY-NC-SA 4.0

Blog materials may be used with attribution to the author and source, for non-commercial purposes, and under the same license.

Start searching

Enter keywords to search articles

↑↓
ESC
⌘K Shortcut