Why would a loop die? - linux

I'm using a simple loop to restart a process if it dies. Occasionally I've seen the loop stop, which of course it shouldn't do. What could be some causes of this? I'm using a low end node/vps running ubuntu 14. Thanks. :)
This is the loop I use.
#!/bin/bash/
period=${1:-60}
while :
do
sleep 20 &
sh restart.sh
wait
done
This is restart.sh.. it greps the current PID of 'ffmpeg' and if its not found, it re-runs the ffmpeg command which broadcasts my own internet radio station, which I can then listen to anywhere :)
#!/bin/bash/
pgrep ffmpeg
if [ $? -ne 0 ]
then killall ffmpeg
killall rtmpdump
sleep 1
nohup ffmpeg (a bunch of ffmpeg stuff) &
fi
So your saying this could be an issue with ffmpeg hanging/freezing, rather then the loop dieing out? Is there ways I could improve what I am doing here? TBH I'm only about a month into linux and a week into bash, so this is the best I could do.
Thanks for your help so far, it was very useful!

Depending on what restart.sh does, it appears the script could wait forever if sh restart.sh hangs. By specifying wait with no PID, it will wait until all process IDs known to the invoking shell have terminated (see man 1P wait). If sh restart.sh hangs, wait is never satisfied.
If there is no specific requirement to background sleep, why not run sleep in the foreground and omit wait altogether:
#!/bin/bash/
period=${1:-60}
while :
do
sleep 20
sh restart.sh
done

Related

Run process in background of shell for 2 minutes, then terminate it before 2 minutes is up BASH

I am using Peppermint distro. I'm new to linux, however I need to display system processes, then create a new process to run in the background for 2 minutes, I need to prove its running and then terminate it before the 2 minutes is up.
So far i'm using xlogo to test my process is working. I have
ps
xlogo &
TASK_PID=$!
if pgrep -x xlogo>/dev/null 2>&1
then
ps
sleep 15
kill $TASK_PID
ps
fi
I can't seem to figure out a way to give it an initial time of 2 minutes but then kill it after 15 seconds anyway.
any help appreciated!
If you want the command to originally have a time limit of 2 minutes you could do
timeout 2m xlogo &
of course, then your $! will be of the timeout command. If you're using pgrep and satisfied it's only finding the process you care about though, you could use pkill instead of the PID to kill the xlogo
Of course, killing the timeout PID will also kill xlogo, so you might be able to keep things as-is for the rest if you're happy with how that works.

Wait for a process launched by another program to terminate

So I'm creating a quick script that basically launches xboxdrv then a game from steam to enable controller support. Yes, while the most games with controller support automatically work with the Xbox 360 controller, there are some games that require you to be running the controller under the xpad driver, else it won't recognize the controller for some reason. The game in question is Bit.Trip Runner 2 on Linux (XUbuntu).
The problem I'm having is trying to get the script to wait for the game to exit (since it gets launched by steam's own commands), and then terminate xboxdrv, to free up memory, but what is happening is when the game exits, I have to go into the terminal and hit Ctrl+C in order to move it along.
If possible, please explain in layman's terms, because this is my first full out batch scrpt for linux. Below is the script in question:
sudo --validate
sudo xboxdrv --silent --detach-kernel-driver --mimic-xpad --dbus session & sleep 2
steam steam://rungameid/$APPID #<-- I want the game to exit to then kill xboxdrv
wait -n $! #<-- If I don't put wait, it will immediately kill xboxdrv after the game launches
sudo killall xboxdrv
exit 0
Well, it seems like the issue was that wait wasn't applying properly, something about child processes. If it wasn't that it was waiting on xboxrdv, it was that it couldn't apply itself properly. After doing a bit more looking around, I happened upon this question, which gave me the code I needed for the wait. So what I ended up doing was adding that bit of code along with a pgrep -x command, so that it could grab and wait on the proper pid.
So in the end, the important part code ended up looking like this:
if [ "$GAMENAME" = "BTR2" ] || [ "$GAMENAME" = "Runner 2" ]; then
APPID=218060
GameProc=[r]unner2
fi
sudo --validate
sudo xboxdrv --silent --quiet --detach-kernel-driver --mimic-xpad --dbus session & sleep 2
steam steam://rungameid/$APPID & sleep 20
check_run_and_grab(){
if ps aux | grep "$GameProc" > /dev/null
then
GamePID=$(pgrep -x "$GameProc")
while kill -0 "$GamePID";do
sleep 5
done
sudo killall xboxdrv
exit 0
else
echo "Game process not found, waiting 5 seconds and trying again"
sleep 5
check_run_and_grab
fi
}
check_run_and_grab
To me, the only thing that would make this better is if it didn't care for capitalization for the game argument (first if statement).

syncing a shell script with kernel operations

For stopping activity in my embedded Linux system, I have the following shell script (interpreted by busybox):
#!/bin/sh
pkill usefulp_program
swapoff /home/.swapfile
umount -l /home
sleep 3 # While I can't find a way to sync, sleep
If I take off the sleep line, the script returns immediately, without waiting even for the umount (which is lazy, as for some reason it refuses to unmount otherwise). Do you know how can I wait for all the three operations to complete before finishing the script? Resorting to an arbitrary sleep does not look like a good solution.
Also, any hint on why I can not umount without the -l?
You need to wait for the killed process to terminate. As per your comment...
wait <pid>
...doesn't work! So, could loop ala:
while ps -p <pid> > /dev/null; do sleep 1; done
to wait for the killed process to terminate before doing the swapoff and umount.
As others already mentioned you should and only the -l when the process is terminated. An option if it takes long/it just ignores you polite request to stop itself is using a different signal. The option would be -9 to the kill/killall/pkill command to send the SIGKILL instead of SIGTERM. If you dont want to use the hammer on your first try you could do something like
pkill your_programm
sleep 10
pkill -9 your_programm

bash: run a command for n minutes, then SIGHUP it

Is there any bash/linux command to launch a long-running command, then kill it after n minutes? I guess I could hack something up with perl using fork and kill, but does anyone know of something already out there?
See the timeout command now in most GNU/Linux distros.
timeout -sHUP 10m command
The same functionality can be achieved with http://www.pixelbeat.org/scripts/timeout
Try it with this one, it starts your command in the background, stores it's PID in $P, waits for some time and kills it with a SIGHUP.
yourCommand & PID=$!
sleep ${someMinutes}m
kill -HUP $PID
Cheers
PS: that assumes a sleep that knows about Nm (minutes), else, you might want to do some math :)
n=5
some_command &
pid=$!
at now + $n minutes <<<"kill -HUP $pid"
The benefit of using at over waiting for sleep is that your script wont block waiting for the sleep to expire. You can go and do other things and at will asynchronously fire at the specified time. Depending on your script that may be a very important feature to have.

Limiting the time a program runs in Linux

In Linux I would like to run a program but only for a limited time, like 1 second. If the program exceeds this running time I would like to kill the process and show an error message.
Ah well. timeout(1).
DESCRIPTION
Start COMMAND, and kill it if still running after DURATION.
StackOverflow won't allow me to delete my answer since it's the accepted one. It's garnering down-votes since it's at the top of the list with a better solution below it. If you're on a GNU system, please use timeout instead as suggested by #wRAR. So in the hopes that you'll stop down-voting, here's how it works:
timeout 1s ./myProgram
You can use s, m, h or d for seconds (the default if omitted), minutes, hours or days. A nifty feature here is that you may specify another option -k 30s (before the 1s above) in order to kill it with a SIGKILL after another 30 seconds, should it not respond to the original SIGTERM.
A very useful tool. Now scroll down and up-vote #wRAR's answer.
For posterity, this was my original - inferior - suggestion, it might still be if some use for someone.
A simple bash-script should be able to do that for you
./myProgram &
sleep 1
kill $! 2>/dev/null && echo "myProgram didn't finish"
That ought to do it.
$! expands to the last backgrounded process (through the use of &), and kill returns false if it didn't kill any process, so the echo is only executed if it actually killed something.
2>/dev/null redirects kill's stderr, otherwise it would print something telling you it was unable to kill the process.
You might want to add a -KILL or whichever signal you want to use to get rid of your process too.
EDIT
As ephemient pointed out, there's a race here if your program finishes and the some other process snatches the pid, it'll get killed instead. To reduce the probability of it happening, you could react to the SIGCHLD and not try to kill it if that happens. There's still chance to kill the wrong process, but it's very remote.
trapped=""
trap 'trapped=yes' SIGCHLD
./myProgram &
sleep 1
[ -z "$trapped" ] && kill $! 2>/dev/null && echo '...'
Maybe CPU time limit (ulimit -t/setrlimit(RLIMIT_CPU)) will help?
you could launch it in a shell script using &
your_program &
pid=$!
sleep 1
if [ `pgrep $pid` ]
then
kill $pid
echo "killed $pid because it took too long."
fi
hope you get the idea, I'm not sure this is correct my shell skills need some refresh :)
tail -f file & pid=$!
sleep 10
kill $pid 2>/dev/null && echo '...'
If you have the sources, you can fork() early in main() and then have the parent process measure the time and possibly kill the child process. Just use standard system calls fork(), waitpid(), kill(), ... maybe some standard Unix signal handling. Not too complicated but takes some effort.
You can also script something on the shell although I doubt it will be as accurate with respect to the time of 1 second.
If you just want to measure the time, type time <cmd ...> on the shell.
Ok, so just write a short C program that forks, calls execlp or something similar in the child, measures the time in the parent and kills the child. Should be easy ...

Resources