How to repeatedly start and kill a never ending bash process - bash

How do I repeatedly start and kill a bash script that takes a long time. I have a analyze_realtime.sh that runs indefinitely, but I only want to run it for X second bursts (just say 15s for now).
while true; do analyze_realtime.sh; sleep 15; done
The problem with this is that analyze_realtime.sh never finishes, so this logic doesn't work. Is there a way to kill the process after 15 seconds, then start it again?
I was thinking something with analyze_realtime.sh&, ps, and kill may work. Is there anything simpler?

while true;
do
analyze_realtime.sh &
jobpid=$! # This gets the pid of the bg job
sleep 15
kill $jobpid
if ps -p $jobpid &>/dev/null; then
echo "$jobpid didn't get killed. Moving on..."
fi
done
You can do more under the if-statement, sending other SIGNALs if SIGHUP didn't work.

Try this out
while true; do
analyze_realtime.sh & # put script execution in background
sleep 15
kill %1
done
Explanation
%1 refer to the latest process ran in background

You can use timeout utility from coreutils:
while true; do
timeout 15 analyze_realtime.sh
done
(Inspired by this answer)

Related

Trying to close all child processes when I interrupt my bash script

I have written a bash script to carry out some tests on my system. The tests run in the background and in parallel. The tests can take a long time and sometimes I may wish to abort the tests part way through.
If I Control+C then it aborts the parent script, but leaves the various children running. I wish to make it so that I can hit Control+C or otherwise to quit and then kill all child processes running in the background. I have a bit of code that does the job if I'm running running the background jobs directly from the terminal, but it doesn't work in my script.
I have a minimal working example.
I have tried using trap in combination with pgrep -P $$.
#!/bin/bash
trap 'kill -n 2 $(pgrep -P $$)' 2
sleep 10 &
wait
I was hoping that on hitting control+c (SIGINT) would kill everything that the script started but it actually says:
./breakTest.sh: line 1: kill: (3220) - No such process
This number changes, but doesn't seem to apply to any running processes, so I don't know where it is coming from.
I guess if the contents of the trap command get evaluated where the trap command occurs then it might explain the outcome. The 3220 pid might be for pgrep itself.
I'd appreciate some insight here
Thanks
I have found a solution using pkill. This example also deals with many child processes.
#!/bin/bash
trap 'pkill -P $$' SIGINT SIGTERM
for i in {1..10}; do
sleep 10 &
done
wait
This appears to kill all the child processes elegantly. Though I don't properly understand what the issue was with my original code, apart from sending the correct signal.
in bash whenever you you use & after a command it places that command as a background job ( this background jobs are called job_spec ) which is incremented by one until you exit that terminal session. You can use the jobs command to get the list of the background jobs running. To work with this jobs you have to use the % with the job id. The jobs command also accept other options such as jobs -p to see the proces sids of all jobs , jobs -p %JOB_SPEC to see the process of id of that particular job.
#!/usr/bin/env bash
trap 'kill -9 %1' 2
sleep 10 &
wait
or
#!/usr/bin/env bash
trap 'kill -9 $(jobs -p %1)' 2
sleep 10 &
wait
I implemented something like this few years back, you can take a look at it async bash
You can try something like the following:
pkill -TERM -P <your_parent_id_here>

Stop a script after a given time in Unix bash

I have a bash script which is runnnig another script. What i want is something like this :
#in scriptA.sh
./scriptB
wait 10 seconds and kill scriptB
Is it doable ?
Thanks.
./scriptB &
sleep 10s
kill $!
How it works
./scriptB &
This starts scriptB in the background.
sleep 10s
This waits 10 seconds
kill $!
This kills the most recently executed background process.
kill will kill any process given is process ID. $! is the process ID of the most recently executed background process.

run forked process continuously, kill after interval

i'm having a difficult time writing a bash script, hoping someone could help. basically i'm trying to run a number of processes at the same time and then kill them all after an interval.
so for example, if i want to run my_long_running_task 50 times and kill after 10 minutes this is what i came up with:
#!/bin/bash
PIDS=()
(while :
do
my_long_running_task;
sleep 1
done ) &
PIDS+=($!)
...{repeat while loop 50 times or stick it in a for loop)...
sleep 600; # 10 minutes * 60 seconds
for p in "${PIDS[#]}"
do
kill $p
done
i'm not a bash expert but that seems like it should work - fork all the processes adding their pids to an array. then at the end just sleep for a certain amount of time before iterating over the array and killing all the pids. and indeed this worked for my very simple poc:
#!/bin/bash
PIDS=()
(while :
do
echo '1'
sleep 1;
done) &
PIDS+=($!)
(while :
do
echo '2'
sleep 1;
done) &
PIDS+=($!)
(sleep 10; \
for p in "${PIDS[#]}"
do
kill $p
done)
but when i do something more interesting than echo - like, in my case, running phantomjs, the processes don't get killed after the interval.
any thoughts? what am i missing?
Your wish is my command (at least, when your wish aligns sufficiently with my desires):
When you run phantomjs, do you run it with exec or just as a normal process?
Does it make any difference if you do use exec?
The thought behind the questions is that you kill the shell that runs the other process (which, in the case of echo, is the shell), but that doesn't necessarily kill the children of the process. Maybe you need to use something like:
kill -TERM -- -$p
kill -- -$p
to send a signal to the process group, rather than just the process.
Also, consider whether a 'time out' command would make your life easier (timeout on Linux).

close feh, and return to shell script

I am trying to write a script that displays an image for a time, then returns back to the shell script. I tried:
feh outfile.jpeg | sleep 10 | exit
but this doesn't work. Im not interested in exiting the script, only in getting back to the other functions of the script.
I just want to show the image for a short time, then return to what the script is doing.
How might I achieve this?
You could do:
feh outfile.jpeg & # run process in background
pid=$! # obtain PID of last backgrounded process
sleep 10
kill $pid # kill feh
Here is a working solution:
(feh outfile.jpeg&) && (sleep 10 && pkill feh)
It will run feh in backgroud and then count to 10 before killing feh. A better way would be to kill the right pid though...

start and monitoring a process inside shell script for completion

I have a simple shell script whose also is below:
#!/usr/bin/sh
echo "starting the process which is a c++ process which does some database action for around 30 minutes"
#this below process should be run in the background
<binary name> <arg1> <arg2>
exit
Now what I want is to monitor and display the status information of the process.
I don't want to go deep into its functionality. Since I know that the process will complete in 30 minutes, I want to show to the user that 3.3% is completed for every 1 min and also check whether the process is running in the background and finally if the process is completed I want to display that it is completed.
could anybody please help me?
The best thing you could do is to put some kind of instrumentation in your application,
and let it report the actual progress in terms of work items processed / total amount of work.
Failing that, you can indeed refer to the time that the thing has been running.
Here's a sample of what I've used in the past. Works in ksh93 and bash.
#! /bin/ksh
set -u
prog_under_test="sleep"
args_for_prog=30
max=30 interval=1 n=0
main() {
($prog_under_test $args_for_prog) & pid=$! t0=$SECONDS
while is_running $pid; do
sleep $interval
(( delta_t = SECONDS-t0 ))
(( percent=100*delta_t/max ))
report_progress $percent
done
echo
}
is_running() { (kill -0 ${1:?is_running: missing process ID}) 2>& -; }
function report_progress { typeset percent=$1
printf "\r%5.1f %% complete (est.) " $(( percent ))
}
main
If your process involves a pipe than http://www.ivarch.com/programs/quickref/pv.shtml would be an excellent solution or an alternative is http://clpbar.sourceforge.net/ . But these are essentially like "cat" with a progress bar and need something to pipe through them. There is a small program that you could compile and then execute as a background process then kill when things finish up, http://www.dreamincode.net/code/snippet3062.htm that would probablly work if you just want to dispaly something for 30 minutes and then print out almost done in the console if your process runs long and it exits, but you would have to modify it. Might be better just to create another shell script that displays a character every few seconds in a loop and checks if the pid of the previous process is still running, I believe you can get the parent pid by looking at the $$ variable then check if it is still running in /proc/pid .
You really should let the command output statistics, but for simplicity's sake you can do something like this to simply increment a counter while your process runs:
#!/bin/sh
cmd & # execute a command
pid=$! # Record the pid of the command
i=0
while sleep 60; do
: $(( i += 1 ))
e=$( echo $i 3.3 \* p | dc ) # compute percent completed
printf "$e percent complete\r" # report completion
done & # reporter is running in the background
pid2=$! # record reporter's pid
# Wait for the original command to finish
if wait $pid; then
echo cmd completed successfully
else
echo cmd failed
fi
kill $pid2 # Kill the status reporter

Resources