0

A command can be scheduled to run periodically by cron.

I was wondering how we can run a command in background periodically in a given interactive bash shell?

  • I would like to run the command from a given interactive bash shell, instead of other shells that are running, because I need the command to generate output based on the state of the shell, e.g. output of jobs in the given shell.

  • I would like to run the command in background, because I would like to be able to continue to run other commands in the same shell

  • the command may be a script, and to let the script access the state of a given shell, I might need to source the script in the shell.

For example:

I wrote an example of such a script:

$ pwd
/tmp/test
$ cat test.sh 
#! /bin/bash

while true;
do
    dirs -l -p  > /tmp/test/dirs
    jobs > /tmp/test/jobs
    sleep 5
done

and then run it in an interactive bash shell:

$ source test.sh &

but the files which get up-to-date output of the script don't contain the output of jobs or dirs -l -p which are directly run in the given shell:

$ evince &
$ jobs
[1]-  Running                 source test.sh &
[2]+  Running                 evince &
$ cat /tmp/test/jobs 
$

$ pushd /tmp/
/tmp /tmp/test    
$ dirs -l -p
/tmp/test
/tmp    
$ cat /tmp/test/dirs 
/tmp/test

I was wondering why? How can we accomplish the task at the beginning of the post?

Thanks.

  • scripts with a while true cycle and sleep as the most basic approach. – Rui F Ribeiro May 5 '18 at 3:05
  • 1
    jobs must have an interactive terminal, I think. Processing power low here atm, 0430AM. – Rui F Ribeiro May 5 '18 at 3:30
1

There are two issues:

  1. The script runs in a non-interactive subshell (different form the parent shell).
  2. The subshell does not have job control.

Simply enabling job control in the subshell by starting the script using bash -m test.sh & will not work since this also means that it will inherit all the file descriptors from the parent shell. The first thing that will happen when you press Enter is that the script will be suspended.

Instead, lets interpret "periodically" as "every time I press Enter to execute a new command".

This means that we can put the main part of the script in PROMPT_COMMAND instead. If this variable has a value, it is evaluated before issuing the next prompt.

PROMPT_COMMAND='jobs >/tmp/test/jobs'

If we run sleep 100 & after this at the prompt and investigate /tmp/test/jobs, we will see that it contains

[1]+  Running                 sleep 100 &

After 100 second, if no further background jobs are started, pressing Enter will update the file to contain

[1]+  Running                 sleep 100 &
[1]+  Done                    sleep 100

After the next Enter, the file will be empty.

  • Thanks. (1) "The script runs in a non-interactive subshell". Is "the noninteractive subshell" created for backgrounding the job? If I am correct, sourceing a script doesn't create a subshell. – Tim May 5 '18 at 16:00
  • (2) "Simply enabling job control in the subshell by starting the script using bash -m test.sh & will not work since this also means that it will inherit all the file descriptors from the parent shell." What is "this also means that it will inherit all the file descriptors from the parent shell" the reason of "Simply enabling job control in the subshell by starting the script using bash -m test.sh & will not work"? – Tim May 5 '18 at 16:01
  • (1) Yes, starting a command in the background runs it in a subshell. Correct, sourcing a script will run it in the current environment (but you can't source a script "in the background"). (2) I'm a bit hazy on this, but I believe they are connected. – Kusalananda May 5 '18 at 17:49

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.