Monday, August 17, 2015

double fork to avoid zombies

No, I'm not talking about our favorite villains. I am talking about orphaned computer processes that could end up as "zombie" processes when you look at "top" command results.

This is for IT aka nerdy types who do shell scripting in BASH or other major shells.

I initially found this method of avoiding process zombies somewhere on the internet. However, I just now searched for it and with small, but too much effort, I did not easily locate it again. --- Update --- I realized upon creating this post, that I had an unexplained example of this in my previous post "self-healing cron job".

So, here it is for future reference.

We wish to prevent creation of a zombie process, and we also wish our newly spawned process to be independent, in case we decide to close our shell.

This can be done in BASH using either nohup ... &, or ... Ctrl-z, disown.
A decent reference for this is here.

nohup YourCommandHere &

OR

YourCommandHere
Press Ctrl-z
disown

I don't recall all the advantages / disadvantages of the above methods. However, some day you may find yourself in a shell that is not BASH, that may not have the nohup and disown commands available.

This should work in all the major shells. It redirects all output to the "ether" commonly known as /dev/null by using 0<&- &>/dev/null. It also double forks and "disowns" using (( &) &). If I understand correctly, the reason for double instead of single fork is to make the newly created process 100% completely independent AND (this is important) force process id 1 to adopt the newly minted process. Process id 1 is god of everything on that computer, and will do all necessary management / clean up. That way, you can leave and go live on some beautiful island and forget about all your children. :) ----- (Please don't do this in your real life!)

(( YourCommandHere 0<&- &>/dev/null &) &)

Hope that helps somebody out there! It will help me, the next time I'm searching for it on Google.

Sunday, August 16, 2015

self-healing cron job

I have been working on some automation. I recently broke it. At least the first iterations broke. Within a couple of minutes, retries do work. Now I should debug and figure out why. But for now my head hurts, I simply want it to work - even the "first time" the cron daemon attempts to run it, even if delayed.

Here follows the magic.

As an example the cronjob entry is something similar to:
# run every 30 minutes at top and bottom of every hour of every day
0,30 * * * * bash -l -c 'WittCron01' >> /dev/null 2>&1

cat WittCron01 
#!/bin/bash

# top priority cron job - kill any already running Automate scripts - start Automate

# kill any instances of Automate
pkill -f Automate

(( DISPLAY=:0 Automate 0<&- &>/dev/null &) &)

# give that instance of Automate some time to prove it can stay alive :)
sleep 10

# if Automate is still running after the above sleep 10
# then kill this and all instances of WittCron01
# else start a new instance of WittCron01
pgrep -f Automate && pkill -f WittCron01 || WittCron01


There you go.

Saturday, August 1, 2015

multi-line comments in shell script

The standard and the general practice of newcomers and veteran shell scripters alike is to use the '#' to indicate a comment in shell script. For example:
# this is a comment

and if done carefully, it can be done at end of a line like:
echo yada yada yada # this is a comment

For multiple lines of comments, every line of the comment needs its own '#' at the beginning, like:
# a comment
# more comment stuff
# tedium ... comments yada

If, for whatever your reasons, you don't wish to do a '#' at beginning of every line, then you can do something like this:

#!/bin/bash

echo See http://unix.stackexchange.com/questions/37411/multiline-shell-script-comments-how-does-this-work
echo
echo My example ignores the multi-line comments in the middle of a loop
for thing in one two three
do
  echo Step ${thing}
: <<'<COMMENT'

This is an abuse of the null command ':' and the here-document syntax
to achieve a "multi-line comment".  According to the POSIX spec linked
above, if any character in the delimiter word ("end_long_comment" in
this case) above is quoted, the here-document will not be expanded in
any way.  This is **critical**, as failing to quote the "end_long_comment"
will result in the problems with unintended expansions described above.
All of this text in this here-doc goes to the standard input of :, which
does nothing with it, hence the effect is like a comment.  There is very
little point to doing this besides throwing people off.  Just use '#'.

# just in case previous line escapes the end of line
<COMMENT
  date
  echo
  sleep 1
done
echo after multi line comments

#

This will produce results of:
See http://unix.stackexchange.com/questions/37411/multiline-shell-script-comments-how-does-this-work

My example ignores the multi-line comments in the middle of a loop
Step one
Sat Aug  1 22:18:54 CDT 2015

Step two
Sat Aug  1 22:18:55 CDT 2015

Step three
Sat Aug  1 22:18:56 CDT 2015

after multi line comments