Shell Script time control - linux

I am running a shell script which runs for ONCE or twice a week..
and this program runs for few hours (depends on how many files) a day..
But problem is, I have to pause this program during the working hours..
for example, if the working hour is 1 am to 3 am, then all the script work should pause and wait till 3:01 am to start again..
i don't have to KILL the current running process if it is running after 1 am..
but whenever it is done with that specific FILE, I have to make it pause for next files..
currently this is what i figure out
while true
do
curr_time= date +"%H%M%S"
if [ $curr_time -ge 005000 -a $curr_time -le 030000 ]
then
echo "Pause for 12000 seconds"
sleep 12000
else
break;
fi
done
So start pausing at 12:50 instead of hoping that everything can phase before 1am
and sleep for 12000 sec which is about 3 hours and restart..
but the problem is if for some reason, when it wakes up from 12000second sleep and it is not 3 am yet, it will sleep for another 12000 seconds..
how can I go around with this ??
i want it to pause around 1 am (each file process takes about 1 minute but few hundreds and thousands files are there to process) and starts RIGHT BACK AT 3 am..
I don't have to kill it if it passes 1 am.. just pause after that file is done processing.

As your question is tagged with bash, you might use arithmetic expansion to just sleep the needed number of seconds.
sleep $(($(date -d 3:01 +%s) - $(date +%s)))
date -d 3:01 +%s should tell the number of seconds since the epoch until 3:01, date +%s the number of seconds since the epoch until now.
The difference should be the number of seconds you have to wait until 3:01.

Related

Linux - Run script after time period expires

I have a small NodeJS script that does some processing. Depending on the amount of data needing to be processed, this can take a couple of seconds to hours.
What I want is to do is schedule this command to run every hour after the previous attempt has completed. I'm wary of using something like cron because I need to ensure that two instances of the script aren't running at the same.
If you really don't like cron (or at) you can just use a simple bash script:
#!/bin/bash
while true
do
#Do something
echo Invoke long-running node.js script
#Wait an hour
sleep 3600
done
The (obvious) drawback is that you will have to make it run in background somehow (i.e. via nohup or screen) and add a proper error handling (taking that you script might fail, and you still want it to run again in an hour).
A bit more elaborate "custom script" solution might be like that:
#!/bin/bash
#Settings
LAST_RUN_FILE=/var/run/lock/hourly.timestamp
FLOCK_LOCK_FILE=/var/run/lock/hourly.lock
FLOCK_FD=100
#Minimum time to wait between two job runs
MIN_DELAY=3600
#Welcome message, parameter check
if [ -z $1 ]
then
echo "Please specify the command (job) to run, as follows:"
echo "./hourly COMMAND"
exit 1
fi
echo "[$(date)] MIN_DELAY=$MIN_DELAY seconds, JOB=$#"
#Set an exclusive lock, or skip execution if it is already set
eval "exec $FLOCK_FD>$FLOCK_LOCK_FILE"
if ! flock -n $FLOCK_FD
then
echo "Lock is already set, skipping execution."
exit 0
fi
#Last run timestamp
if ! [ -e $LAST_RUN_FILE ]
then
echo "Timestamp file ($LAST_RUN_FILE) is missing, creating a new one."
echo 0 >$LAST_RUN_FILE
fi
#Compute delay, and wait
let DELAY="$MIN_DELAY-($(date +%s)-$(cat $LAST_RUN_FILE))"
if [ $DELAY -gt 0 ]
then
echo "Waiting for $DELAY seconds, before proceeding..."
sleep $DELAY
fi
#Proceed with an actual task
echo "[$(date)] Running the task..."
echo
"$#"
#Update the last run timestamp
echo
echo "Done, going to update the last run timestamp now."
date +%s >$LAST_RUN_FILE
This will do 2 things:
Set an exclusive execution lock (with flock), so that no two instances of the job will run at the same time, irregardless of how you start them (manually or via cron e.t.c.);
If the last job was completed less then MIN_DELAY seconds ago,
it will sleep for the remaining time, before running the job again;
Now, if you schedule this script to run, say every 15 minutes with cron, like that:
* * * * * /home/myuser/hourly my_periodic_task and it's arguments
It will be guaranteed to execute with the fixed delay of at least MIN_DELAY (one hour) since the last job completed, and any intermediate runs will be skipped.
In the worst case, it will execute in MIN_DELAY + 15 minutes,
(as the scheduling period is discrete), but never earlier than that.
Other non-cron scheduling methods should work too (i.e. just running this script in a loop, or re-scheduling and each run with at).
You can use a cron and add process.exit(0) to your node script

get average of times that take job finish in for loop shell script

Here is my first shell script
#!/bin/bash
COUNTER=0
while [ $COUNTER -lt 10000 ]; do
date;
time wget -q 'http://exmple.com/' > /dev/null | grep real;
sleep 3;
let COUNTER=COUNTER+1
done
echo ${COUNTER} Request Sent\n
Average Response Time is :
this script download page content and calculate time of page response
i need to store Real parameter and calculate average of it
the output of script is something like that
Tue Oct 25 22:43:36
real 0m13.275s
user 0m0.004s
sys 0m0.008s
So my problems are :
How can i add some jobs (like echo ${COUNTER} ) after pressing crtl+c (stopping script)
How can i store value of "real" in seconds // sometimes page response goes to minutes , so basically need some time convert function (?)
i tried to solve the problems but as i mentioned i am training shell script
#!/bin/bash
echo "How many runs would you like to perform?"
read limit
total_time=0
counter=1
while [ ${counter} -le ${limit} ]
do
date
run_time=`(time -p wget -qO- http://exmple.com/) 2>&1 > /dev/null | grep real | awk '{print $2}'`
echo "Run ${counter} completed in ${run_time} seconds"
total_time=$(bc<<<"${total_time}+${run_time}")
if [ ${counter} -ne ${limit} ]
then
sleep 3
let counter=counter+1
fi
done
avg=$(printf "%.3f" "$(bc -l <<<"${total_time}/${limit}")")
echo "${counter} requests were sent taking ${total_time} seconds"
echo "Average response time was : ${avg} seconds"
Above is a modified script to perform the operations you requested, with a couple modifications
Added a question then input to ask how many runs to make each time, instead of a static number
Print out total time for runs and then average per run in 3 decimal places
Skip sleeping if it's the last run
You'll notice we use bc instead of let for a couple math lines. The bc command allows the use of decimal places.
https://www.gnu.org/software/bc/manual/html_mono/bc.html
To get the value in seconds I had to use awk to separate the value from the title 'real' in the line. Then you can do the math on the number value.
One other thing I noticed in your initial script. You used both ways of displaying a variable:
$COUNTER and ${COUNTER}
While both are legitimate, I got into the habit of always encapsulating my variables, it makes things easier when you want to add to the end of it.
For example let's say I have a number defined (NUM=7), but want to display it times 10. If I don't encapsulate echo $NUM0 then I get an error because the variable $NUM0 wasn't defined. But if I encapsulate echo ${NUM}0 will display an output of 70.
All of this results in a final output as below
How many runs would you like to perform?
5
Tue Oct 25 16:02:58 MST 2016
Run 1 completed in 0.09 seconds
Tue Oct 25 16:03:01 MST 2016
Run 2 completed in 0.08 seconds
Tue Oct 25 16:03:05 MST 2016
Run 3 completed in 0.07 seconds
Tue Oct 25 16:03:08 MST 2016
Run 4 completed in 0.09 seconds
Tue Oct 25 16:03:11 MST 2016
Run 5 completed in 0.08 seconds
5 requests sent taking .41 seconds
Average response time was : 0.08 seconds
Please let me know if you have any other questions about the script.
You can record a reasonably precise time with e.g.
t1=$(date +%s.%N)
wget ...
t2=$(date +%s.%N)
diff=$(($t2-$t1))
For doing stuff after Ctrl+C, which is really a SIGINT signal, read up about the trap builtin.

Bash script: CPU stress test while watching clock speed

I am totally new to this forum and also new to bash, so please bear with me :).
I would like to write a bash script to conduct a CPU stress test while observing the clock speed. Therefore, I have done the following:
1.) For the CPU stress test, I have created a script named "bernoulli" with the following code:
#!/bin/bash
# argument 1: n
function bernoulli()
{
if (( $1 < 3 ))
then
echo 1
else
echo $(( $(bernoulli $(( $1 - 1 ))) + $(bernoulli $(( $1 - 2 ))) ))
fi
}
bernoulli $1
2.) I have figured out that by using the "timeout" command I can kill a task after a specified time. For example,
timeout 30s ./bernoulli 35
starts a task calculating the 35th bernoulli number and the task is killed after 30 seconds.
3.) I also found out that by typing
timeout 30s watch grep \"cpu MHz\" /proc/cpuinfo
I can watch the clock speed of my cores (updated every 2 seconds) for 30 seconds (at which point "timeout 30s" kills this task).
What I want: I would like to do the above stress test and simultaneously observe the clock speed. In other words, I would somehow run the two commands
timeout 30s ./bernoulli 35
timeout 30s watch grep \"cpu MHz\" /proc/cpuinfo
"at the same time". I hope I could make it clear what I would like to achieve. Can anyone help with my issue? Thanks a lot for every comment!
How about
timeout 30s ./bernoulli 35 &
timeout 30s watch grep \"cpu MHz\" /proc/cpuinfo
& at the end will make command to run at background, so that second timeout will be executed almost instantly after the first one.
PS: this is rather poor way to test modern CPU. You will be exercising only single core and most likely only limited part of your CPU (no sse, etc). It is not trivial to write CPU benchmark, so you might want to use one of already available. For example, you can take a look at sysbench with something like sysbench --test=cpu --cpu-max-prime=20000 run.
You can run them in a dedicated shell:
timeout 30s bash -c './bernoulli 35 & watch grep \"cpu MHz\" /proc/cpuinfo'
Note that the single & is not a typo. It is not a logical and, it runs the bernoulli script in background.

Shell infinite loop to execute at specific time [duplicate]

This question already has answers here:
Sleep until a specific time/date
(22 answers)
Closed 7 years ago.
I have access to a Linux CentOS box. (I can't use crontab sadly)
When I need to run a task everyday I have just created a infinite loop with a sleep. (it runs, sleeps ~24 hours and then runs again)
#!/bin/sh
while :
do
/home/sas_api_emailer.sh |& tee first_sas_api
sleep 1438m
done
Recently I have a task that I need to run at a specific time everyday 6:00 am (I can't use crontab)
How can I create an infinite loop that will only execute # 6:00 am?
Check the time in the loop, and then sleep for a minute if it's not the time you want.
while :
do
if [ $(date '+%H%M') = '0600' ]
then /home/sas_api_emailer.sh |& tee first_sas_api
fi
sleep 60
done
You have (at least!) three choices:
cron
This is hands-down the best choice. Unfortunately, you say it's not an option for you. Drag :(
at
at and batch read commands from standard input or a specified file
which are to be executed at a later time.
For example: at -f myjob noon
Here is more information about at: http://www.thegeekstuff.com/2010/06/at-atq-atrm-batch-command-examples/
Write a "polling" or "while loop" script. For example:
while true
# Compute wait time
sleep wait_time
# do something
done
Here are some good ideas for "compute wait time": Bash: Sleep until a specific time/date

Bash script how to sleep in new process then execute a command

So, I was wondering if there was a bash command that lets me fork a process which sleeps for several seconds, then executes a command.
Here's an example:
sleep 30 'echo executing...' &
^This doesn't actually work (because the sleep command only takes the time argument), but is there something that could do something like this? So, basically, a sleep command that takes a time argument and something to execute when the interval is completed? I want to be able to fork it into a different process then continue processing the shell script.
Also, I know I could write a simple script that does this, but due to some restraints to the situation (I'm actually passing this through a ssh call), I'd rather not do that.
You can do
(sleep 30 && command ...)&
Using && is safer than ; because it ensures that command ... will run only if the sleep timer expires.
You can invoke another shell in the background and make it do what you want:
bash -c 'sleep 30; do-whatever-else' &
The default interval for sleep is in seconds, so the above would sleep for 30 seconds. You can specify other intervals like: 30m for 30 minutes, or 1h for 1 hour, or 3d for 3 days.

Resources