Reputation: 383
I have written a shell script run.sh
to trigger a few tasks based on the user's input
#!/bin/bash
echo "Please choose mode [1-3]: "
read MODE
case $MODE in
1)
echo -n "Enter iteration: "
read TIME
echo "Start Updating ..."
task 1 && task 2 && task 3
;;
2)
echo -n "Enter Seed Value: "
read SEED
echo "Start Updating ..."
task 4
task 5
;;
3)
echo -n "Enter regression minimum value: "
read MIN
echo "Start Updating ..."
task 6
;;
*)
echo -n "Unknown option - Exit"
;;
esac
The tasks 1,2 ... 6 are php scripts that are run like /usr/bin/php task1.php $TIME
with $TIME as an argument for the php script etc...
The script runs fine when I type bash run.sh
but since tasks 1-6 takes a long time to complete I would like an option to run the script in background while I disconnect from the terminal. However if I run the script using bash run.sh &
I encountered an error like this:
Please choose mode [1-3]: 2
-bash: 2: command not found
[5]+ Stopped bash run.sh
It seems like bash interpreted my input 2
as an argument not corresponding to read MODE
but instead of bash run.sh 2
which causes an error. I cannot change the script such that tasks 1-6 are run in the background like task 1 &
task 2 &
etc. because task 2 can only start running after task 1 is completed.
How can I accomplish what I want to do?
Upvotes: 3
Views: 3170
Reputation: 126038
Short answer: running interactive programs (/scripts) in the background doesn't really work; it'll work even less well if you disconnect from the terminal. You should rewrite the script so it doesn't need user input as it runs.
Long answer: when you run the script in the background, something like this happens. Note that the exact order of events may vary, as both the background script and foreground interactive shell are running at the same time, "racing" each other to get things done.
bash run.sh &
read
from the terminal... but it's in the background, so it's not allowed to. Instead, it is suspended, and a "Stopped" message is printed. From the bash man page, "Job Control" section:Background processes which attempt to read from (write to when
stty tostop
is in effect) the terminal are sent aSIGTTIN
(SIGTTOU
) signal by the kernel's terminal driver, which, unless caught, suspends the process.
At this point, if you want to continue the script and tell it what to do, you'd need to move it to the foreground (e.g. with the fg
) command. Which would kind of negate the point here. Also, its prompt ("Please choose mode [1-3]: ") will not be repeated, as that echo
command successfully finished while it was in the background.
The solution: basically, write the script to non-interactively run the tasks in the necessary order. @Lenna has given examples; follow her recommendations.
Upvotes: 1
Reputation: 1290
You could run all of those tasks sequentially in a background subshell
( task 1; task 2; task 3 ) &
Try this out with:
( echo "One"; sleep 1; echo "Two"; sleep 2; echo "Three"; sleep 3; echo "Done" ) &
You could also make this more script-looking:
(
echo "One"
sleep 1
echo "Two"
sleep 2
echo "Three"
sleep 3
echo "Done"
) &
Feel free to make use of the useful envar $BASH_SUBSHELL
( echo $BASH_SUBSHELL; ( echo $BASH_SUBSHELL ) )
Upvotes: 8