1

I am writing a bash script in which I must execute 3 commands.

  • Command 1 must run every 10 seconds, in the background
  • Commands 2 and 3 must run once and also in the background.
  • Also, command 1 must execute at least once, successfully, before command 2 and 3 execute, because it produces/updates a file that the last 2 will need for proper functioning.

However, I don't know how to make command 1 run with these conditions... I cannot use a while(1) with a sleep 10 or something of the kind, because then I would never reach the commands 2 and 3.

What bash script concept am I missing? Threads, maybe?

Edit: Command 1 can be something as simple as incrementing integer number inside a .txt file and this file will be used in command 2 and 3.

  • What if command 1 takes more than 10s to run? – guillermo chamorro Oct 23 '19 at 14:22
  • I'm making sure it does not. But again, as I said, one part of the problem is that it must run at least once successfully, before the other two can be executed (so that command 2 and 3 have at least a file to work with, even if the contents are not updated) – imll Oct 23 '19 at 14:28
1

What bash script concept am I missing? Threads, maybe?

Job control. You can start processes in the background and exercise fairly fine-grained control over them by knowing their process ID and exit status.

To get a backgrounded command's PID, use the $! variable.

To get a backgrounded command's exit status use wait() and provide its PID. Note, calls to wait() will block if the command has not exited yet. If this blocking is problem (it may be in your case), you can perform checks with ps (or some other method) before calling wait() to see if your process is ready to be reaped, usually in a loop where there is a watchdog or some other method of setting a limit on the task's execution time.

Consider the following cycle based boilerplate:

complete=0
cycles=0
# Task 1
sleep 200 &
pid=$!
while [[ complete -eq 0 ]]; then
    ps -o pid= -p $pid > /dev/null
    if [[ $? -ne 0 ]]; then
        # Signal complete to logic below
        complete=1
        break;
    fi
    # Perform some timeout / cycle check to give up on this task
    cycles=$((cycles + 1))
    if [[ $cycles -gt 100 ]]; then # whatever, this is just a simple watchdog example
        break;
    fi
    # Optional sleep
    sleep 1
done
if [[ $complete -eq 1 ]]; then
    # Process the command's exit status
    wait $pid
    if [[ $? -ne 0 ]]; then
        : # handle command failed perhaps
    else
        : # do other things, assuming exit of 0 is a good thing
    fi
else
    # Process a command watchdog failure
    kill -9 $pid # come what may
fi

For more complex job control, you can move your command checks and cycle management into bash functions and clean this code up a lot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.