I have a Unix shell script that is as follows:
(
# Trap the HUP signal so it doesn't kill me
trap "" HUP
# Redirect stderr to /dev/null
exec 2>/dev/null
# Redirect stdin from /dev/null
exec 0</dev/null
# Redirect stdout to logfile
exec 1>${LOG}
while [ 1 ]
do
ps -ewwo pcpu,pid,ppid,comm,time,etime,thcount,scount,fuser,args | grep -v "migration" | grep -v "watchdog" | grep -v "ksoftirqd"
sleep 600
done
) &
I want this to run in the background during some tests I am running to capture process information. It runs "ps" with some options and then sleeps for 10 minutes and I want it to run indefinitely (as my tests vary in length).
My problem is that I have no way to stop this - doing a "ps -ef" only shows me the "sleep 600" command and I have no way of breaking the loop. Is there a way to kill this script or would it be better to write it so not to include a never ending loop? My only thought is to write the script to end execution after a certain time limit (ie several sets of 10 minutes) but I would prefer not to have to edit the script before each test.
We're getting into bash golf here, but if don't want to wait the 600 seconds for it to exit, you can have it listen on a named pipe (a.k.a. "fifo") and exit once you talk into the pipe:
Props to http://www.linuxjournal.com/content/using-named-pipes-fifos-bash
The shell subprocess invoked by the
( ... ) &
construct, and all its children, will be in their own process group.The entire process group can be killed in a single action by specifying a negative number as the process ID to
kill
. (To do this you must also specify a signal number.)The PGID to kill is guaranteed to be equal to the PID of its process group leader, which in this case is the shell subprocess. So you can modify your code along the lines of
(Note:
kill -NAME
andtrap "..." NAME
are not portable shell; however, the meanings of signal numbers 1 through 15 are portable all the way back to V7. If total portability is not an overriding concern, don't write a shell script; the moment you are tempted to reach for an unportable feature, instead stop and rewrite the entire thing in Perl, which is not only a superior programming language, it's more likely to be available on a randomly chosen Unix box than Bash is. Your future self will thank you.)(Note to pedants: sadly, no readily available version of POSIX.1 can be taken as the reference for what is and is not portable shell, because several major proprietary-Unix vendors froze their shell environments in 1995 plus or minus two years. For complete portability, as e.g. required for
autoconf
scripting, I'm not aware of a reliable test other than "does this work with Solaris/bin/sh
?" (Just be glad you no longer have to dig up access to HP-UX, IRIX, and AIX as well.) However, I am under the impression that you can code to POSIX.1-2001, although not -2008, if you're only interested in portability to the open-source BSDs, full-scale desktop or server Linux, and OSX. I am also under the impression that Android, busybox, and various other embedded environments do not provide all of -2001.)There are many ways to do this. One relatively easy one would be like this:
Then when you want to kill your loop, just remove the file. It'll abort the loop the next time it checks...