Sunday, April 26, 2026

Conditional Subsequent Command Calls

 

Occasionally there is a need in bash scripting to execute a series of commands in sequence conditionally.  Command2 needs to be run after command1 if, and only if, the command1 succeeded (or failed).

One means of performing this is to execute the command, assign the return value to a variable, and evaluate the return value executing the subsequent command based on the value.

 $ cat -n foo

     1  #!/bin/bash

     2

     3  sleep 1

     4  #sleep -1

     5  rc=$?

     6

     7  echo $rc

     8  if [ $rc == 0 ]; then

     9    echo "run something else"

    10  fi

    11

Note, the above the script executes a sleep command, preserves the return code, and executes the subsequent command (e.g. echo) based on the return value.  Note; we can force a failed return code by specifying a negative sleep duration.

An alternative shortened syntax is to specify the command sequence on a single line using a '&&' or '||' seperator, the seperator determing if the subsequent command should be exectued on success/failure of the preceeding command.

              command1 && command2

 This syntax issues command2 if, and only if, command1 returns an exit status of zero.

        An OR list has the form

               command1 ││ command2

Now, command2  is  executed  if  and only if command1 returns a non-zero exit status.  This can be used to readily define recovery, or notification, behaviors for a failed command. 

The return status of AND and OR lists is the exit status of the last command executed in the list.

      1  #!/bin/bash

     2

     3  sleep 1 && echo "run something else"; #--execute command2 if command1 was successful

     4  sleep -1 || echo "run something else"; #--execute command2 if command1 failed

     5  sleep -1 && echo "run something else"; #--execute command2 if command1 was successful

     6

Sunday, April 19, 2026

Read-Only Variables in Bash

 

Bash has a little known concept of read-only variables.  When specifying 'readonly' during a variable assignment prevents the variable from being reassigned.

 For example;

 1  #!/bin/bash

2

3  readonly x=0

4  echo $x

5  x=1

6  echo $x

Line 3 specifies a read-only assignment of variable x to 0, an attempt to reassign on line 5 will be disregarded and produce an error message.  The error doesn't prevent continuation of the script however.

 

::::::::::::::

Sunday, April 12, 2026

Detect Command Timeouts using Bash

 A common, and often overlooked, need for scripting is addressing hanging, or unresponsive commands.  What should your script do if one of it's ste

ps takes much, much, much longer than expected?  A hanging, or unresponsive, subprocess will result in a hanging job which in turn can prevent oth

er jobs from running.  Let's spend a bit of time how to address such an need.

 

The 'timeout' command is provided by the coreutils package, often readily available on default installation for most distributions.

 

$ sleep 10

$ echo $?

0


 

Execution of subprocesses generally set a return code, zero or non-zero, often zero indicating successful execution of the command, non-zero return codes if it failed for some reason.  The above command sequence will execute a sleep command (for 10 seconds), the second command echoing the return code.  Assignment of $? to zero indicates the sleep command executed successfully.

 

So, what if we wanted to prevent a hanging command to go undetected and/or prevent the rest of a script from running.  Let's say we want to enforce a command takes no longer than 5 seconds.
 

$ timeout 5 sleep 10

$ echo $?

124


 

After 5 seconds, the command terminates, the return code 124 indicates the command timed out.  Usage of this allows setting hard constraints on how long a command is allowed to run before terminating or being terminated.  The return code allows determining if the command timed-out.
 

Cheers.

Sunday, April 5, 2026

Synchronizing Completion of Concurrent Commands

 

Running concurrent commands in a script generally is done by executing processes in the background.  Numerous commands can be spawned concurrently then synchronized by waiting for some, or all, of them to complete before proceeding or terminating the parent script.

     1  #!/bin/bash

     2

     3  sleep 10 &

     4  pId1=$!

     5

     6  sleep 2 &

     7  pId2=$!

     8

     9  sleep 3 &

    10  pId3=$!

    11

    12  echo "waiting for jobs to complete"

    13  #wait ; #--wait for all jobs to complete

    14  wait $pId1 $pId2 $pId3 ; #--wait for specific jobs to complete

 

In the above script, a sequence of sleeping {10, 2, and 3} seconds are executed in sequence, each in the background.  The longest running command  (e.g. 10 seconds in this example) should take 10 seconds, the other two commands concluding earlier.

We can test the proper exection, the script completing in ~10 seconds by timing the execution as follows:

$ time ./foo

waiting for jobs to complete

 

real    0m10.008s

user    0m0.003s

sys     0m0.004s

$

bash-4.1$