Clarification regarding shell script scheduling - bash

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!

Related

How to lock the folder when the bash script is running inside

I have a task flow which can be divided into step_1 and step_2, both running in bash.
step_1 needs run a bash script in folder_a.
when I submit my jobs into multiple hosts, there are multiple threads which will trigger the bash script in folder_a, this will break the function.
I want my jobs run as following :
every job's step_1 has to run one by one, otherwise it will break function in the folder_a.
every job's step_2 can run parallelly for speed.
How to lock the folder if the bash in folder_a is running and refuse to run for other thread ?
Maybe I can only lock the step_1 bash top script inside folder_a, instead of the folder.
If you are working under a Unix-like system (GNU/Linux, BSD...) you probably have flock and you could wrap the critical jobs in flock calls:
step1_job: | folder_a/.lock
flock $| command [arguments]
folder_a/.lock:
touch $#
See man flock for the details.

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

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)

Wait new terminals until die from original terminal using bash shell

I making CI build program.
I using three script
first is for build. second is for asset build. The last is for running the first and second scripts.
I want to wait for the first and second script until they done in The last script.
Here is the test script.
The first script
#!/bin/sh
sleep 1
echo test2
exit 0
The second script
#!/bin/sh
sleep 1
echo test3
exit 0
The last script
#!/bin/sh
open -a /Applications/Utilities/Terminal.app ./screenTest2.sh &
open -a /Applications/Utilities/Terminal.app ./screenTest3.sh &
wait
echo test
how can I wait new terminals die or scripts. I'm newly in OS X. So can you explain easily that solution?
Bash instructions are sequential just remove '&' character at the end of each line. Each instruction will execute one after the other. You can safely remove wait as well it will not be necessary to wait.

Introduce timeout in a bash for-loop

I have a task that is very well inside of a bash for loop. The situation is though, that a few of the iterations seem to not terminate. What I'm looking for is a way to introduce a timeout that if that iteration of command hasn't terminated after e.g. two hours it will terminate, and move on to the next iteration.
Rough outline:
for somecondition; do
while time-run(command) < 2h do
continue command
done
done
One (tedious) way is to start the process in the background, then start another background process that attempts to kill the first one after a fixed timeout.
timeout=7200 # two hours, in seconds
for somecondition; do
command & command_pid=$!
( sleep $timeout & wait; kill $command_pid 2>/dev/null) & sleep_pid=$!
wait $command_pid
kill $sleep_pid 2>/dev/null # If command completes prior to the timeout
done
The wait command blocks until the original command completes, whether naturally or because it was killed after the sleep completes. The wait immediately after sleep is used in case the user tries to interrupt the process, since sleep ignores most signals, but wait is interruptible.
If I'm understanding your requirement properly, you have a process that needs to run, but you want to make sure that if it gets stuck it moves on, right? I don't know if this will fully help you out, but here is something I wrote a while back to do something similar (I've since improved this a bit, but I only have access to a gist at present, I'll update with the better version later).
#!/bin/bash
######################################################
# Program: logGen.sh
# Date Created: 22 Aug 2012
# Description: parses logs in real time into daily error files
# Date Updated: N/A
# Developer: #DarrellFX
######################################################
#Prefix for pid file
pidPrefix="logGen"
#output direcory
outDir="/opt/Redacted/logs/allerrors"
#Simple function to see if running on primary
checkPrime ()
{
if /sbin/ifconfig eth0:0|/bin/grep -wq inet;then isPrime=1;else isPrime=0;fi
}
#function to kill previous instances of this script
killScript ()
{
/usr/bin/find /var/run -name "${pidPrefix}.*.pid" |while read pidFile;do
if [[ "${pidFile}" != "/var/run/${pidPrefix}.${$}.pid" ]];then
/bin/kill -- -$(/bin/cat ${pidFile})
/bin/rm ${pidFile}
fi
done
}
#Check to see if primary
#If so, kill any previous instance and start log parsing
#If not, just kill leftover running processes
checkPrime
if [[ "${isPrime}" -eq 1 ]];then
echo "$$" > /var/run/${pidPrefix}.$$.pid
killScript
commands && commands && commands #Where the actual command to run goes.
else
killScript
exit 0
fi
I then set this script to run on cron every hour. Every time the script is run, it
creates a lock file named after a variable that describes the script that contains the pid of that instance of the script
calls the function killScript which:
uses the find command to find all lock files for that version of the script (this lets more than one of these scripts be set to run in cron at once, for different tasks). For each file it finds, it kills the processes of that lock file and removes the lock file (it automatically checks that it's not killing itself)
Starts doing whatever it is I need to run and not get stuck (I've omitted that as it's hideous bash string manipulation that I've since redone in python).
If this doesn't get you squared let me know.
A few notes:
the checkPrime function is poorly done, and should either return a status, or just exit the script itself
there are better ways to create lock files and be safe about it, but this has worked for me thus far (famous last words)

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