How to know if a.sh is executing from b.sh? - shell

I am running a script a.sh and parallelly I am executing b.sh. Now b.sh should not start executing it's business logic unless a.sh is finished. To achieve that in b.sh, I have a while loop which searches with the name a.sh in ps -ef command, but a.sh has many sleep commands, so when sleep is executing I am not seeing any result in ps -ef command for a.sh, rather the process is like sleep 60
In this scenario, what I can think of is either I set a flag in a.sh which b.sh can access somehow. But I don't know how to access such variable in b.sh because a.sh is not calling b.sh.
Or I can create a child process and give it a custom name and terminate it in the end of a.sh.
In such way, in b.sh I can search for the process with that particular name and till the time it is there I don;t start execution of the business logic in b.sh. But I don't know how to do this either.

Why not let the 2 communicate? For example what you could do :
a.sh writing into some temporary file its progress status
b.sh loop reading the file waiting to see the correct thing in that file to progress.
Note that there might be some easier/safer way to do that in bash (using signals maybe) but I think that should do the job. Be careful though about the concurrent aspect of your problem.
(can't comment not enough rep)

Related

How to run a shell script with the terminal closed, and stop the script at any time

What I usually do is pause my script, run it in the background and then disown it like
./script
^Z
bg
disown
However, I would like to be able to cancel my script at any time. If I have a script that runs indefinitely, I would like to be able to cancel it after a few hours or a day or whenever I feel like cancelling it.
Since you are having a bit of trouble following along, let's see if we can keep it simple for you. (this presumes you can write to /tmp, change as required). Let's start your script in the background and create a PID file containing the PID of its process.
$ ./script & echo $! > /tmp/scriptPID
You can check the contents of /tmp/scriptPID
$ cat /tmp/scriptPID
######
Where ###### is the PID number of the running ./script process. You can further confirm with pidof script (which will return the same ######). You can use ps aux | grep script to view the number as well.
When you are ready to kill the ./script process, you simply pass the number (e.g. ######) to kill. You can do that directly with:
$ kill $(</tmp/scriptPID)
(or with the other methods listed in my comment)
You can add rm /tmp/scriptPID to remove the pid file after killing the process.
Look things over and let me know if you have any further questions.

terminate a running program in the calling shell script

I wrote a shell script, A, in which it calls another script, B. What B does is to run some calculation and create a text file.
I don't own the code of B, and A has to call it in the foreground for non-tech reasons.
it takes less than 1 minute for B to calculate and create the text, however, B won't end itself and return the control to A until 6 minutes later.
Now the user complained why it takes 7 minutes to run script A.
Therefore my question is how can I rewrite A to detect the file is created and thus terminate B immediately to regain the control? if A still has to run B in foreground? is it doable?
hope I've made myself clear.
thanks!
John
This script calls in background a function that check whether the file exists, then using exec run the script with the same pid of the original script (such pid is obtained with $$), when the file is created the kill is sent to this pid and the exec'ed script is then killed:
#!/bin/bash
function checkAndKill {
local pid=$1
local filename=$2
while [ ! -e $filename ]; do
sleep 1
done
kill $pid
}
checkAndKill $$ /path/of/the/file/to/check &
exec B.sh

How to make bash interpreter stop until a command is finished?

I have a bash script with a loop that calls a hard calculation routine every iteration. I use the results from every calculation as input to the next. I need make bash stop the script reading until every calculation is finished.
for i in $(cat calculation-list.txt)
do
./calculation
(other commands)
done
I know the sleep program, and i used to use it, but now the time of the calculations varies greatly.
Thanks for any help you can give.
P.s>
The "./calculation" is another program, and a subprocess is opened. Then the script passes instantly to next step, but I get an error in the calculation because the last is not finished yet.
If your calculation daemon will work with a precreated empty logfile, then the inotify-tools package might serve:
touch $logfile
inotifywait -qqe close $logfile & ipid=$!
./calculation
wait $ipid
(edit: stripped a stray semicolon)
if it closes the file just once.
If it's doing an open/write/close loop, perhaps you can mod the daemon process to wrap some other filesystem event around the execution? `
#!/bin/sh
# Uglier, but handles logfile being closed multiple times before exit:
# Have the ./calculation start this shell script, perhaps by substituting
# this for the program it's starting
trap 'echo >closed-on-calculation-exit' 0 1 2 3 15
./real-calculation-daemon-program
Well, guys, I've solved my problem with a different approach. When the calculation is finished a logfile is created. I wrote then a simple until loop with a sleep command. Although this is very ugly, it works for me and it's enough.
for i in $(cat calculation-list.txt)
do
(calculations routine)
until [[ -f $logfile ]]; do
sleep 60
done
(other commands)
done
Easy. Get the process ID (PID) via some awk magic and then use wait too wait for that PID to end. Here are the details on wait from the advanced Bash scripting guide:
Suspend script execution until all jobs running in background have
terminated, or until the job number or process ID specified as an
option terminates. Returns the exit status of waited-for command.
You may use the wait command to prevent a script from exiting before a
background job finishes executing (this would create a dreaded orphan
process).
And using it within your code should work like this:
for i in $(cat calculation-list.txt)
do
./calculation >/dev/null 2>&1 & CALCULATION_PID=(`jobs -l | awk '{print $2}'`);
wait ${CALCULATION_PID}
(other commands)
done

Clarification regarding shell script scheduling

I have 2 shell scripts say a.sh and b.sh scheduled in cron where the first one a.sh is scheduled to run at 5am and the second script b.sh will run at 7am.
There are pre-conditions which state that :
1) Only one can run at a time.
2) The second script b.sh should run only after the first script a.sh completes.
Now the problem is the first script a.sh may complete its execution before 7am or may exceed 7am in some cases and in the case where it exceeds 7am the second script is also started which will break one of the pre-conditions.
Here I cannot start the second script later that day as its very crucial script.
Here how can I make both the scripts run one after the other without the first script stepping on the second script.
Have the a.sh script create a lockfile when it's complete (last line).
touch ~/a.lck
At the beginning of b.sh:
if [ ! -f ~/a.lck ]; then
exit 1 #or whatever you want it to do if the lock file is not there.
fi
Don't forget to rm the lockfile either at the beginning of a.sh or the end of b.sh!

How to start a shell script in one minute later in linux?

How to start a shell script in one minute later?
Suppose there are two bash files a.sh and b.sh
I want to execute b.sh one minute(or several seconds) after a.sh executed.
what should I code in a.sh ?
Simple. you want to use 'at' to schedule your job. and 'date' to calculate your moment in the future.
Example:
echo b.sh | at now + 1 minute
or:
echo b.sh | at -t `date -v+60S "+%Y%m%d%H%M%S"`
-v+60S adds 60 seconds to current time. You can control exactly how many seconds you want to add.
But usually, when people wants one program to launch a minute after the other, they are not 100% sure it will not take more or less than a minute. that's it. b.sh could be launched before a.sh is finished. or a.sh could have finished 30 seconds earlier than "planned" and b.sh could have started faster.
I would recommend a different model. Where b.sh is launched first.
a.sh creates a temp file when it starts. execute is tasks and delete its temp file at the end.
b.sh watch for the temp file to be created, then deleted. and start its tasks.
Make the final line of a.sh:
sleep 60 && b.sh
(If b.sh is not in a directory in PATH, make that a full path to b.sh.)
You can just sleep:
a.sh
sleep 60
b.sh
Or for more complicated cases you can use the at command:
echo b.sh | at now + 1 minute
See the at man page for more information.
Use the at command.
See man at for how to use it.
You could use the command to sleep your script for 1 minute.
sleep 1m
Then when you wish to call the 2nd script
bash a.sh
If you want to execute the second script some number of seconds after the start of the first script, you can do this in the first:
b.sh &
and this in the second:
sleep 10
# more commands
You could pass the number of seconds as an argument from the first to the second.
Unfortunately, at doesn't do time increments finer than one minute.
Schedule both the scripts to run at the same time in cron and put the required delay in b.sh.

Resources