I'm William L. Dye ("willdye"), a programmer from Lincoln, Nebraska, USA. I'm not a Bash expert, but I've contributed to this wiki in the past, and might contribute again sometime, so I might as well create an account here.

I typically program in C/C++, Tcl/Tk, and Bash; and occasionally program in Python, Awk, and Lisp. I can't even remember all the languages I've used over the years, but it's a long list (Fortran, APL, various assembers, et alibi). I can also use Java. If I have to. I guess.

I currently program on the Windows and Linux platforms, mostly in the Vista and Ubuntu varieties. In the past, I've used IBM mainframes (mostly 370 MVS), BSD, HP/UX, and Macintosh. In acient days of long ago, I've used CP/M, DOS, Amiga, CDC mainframes, TRS-80, Commodore 64, Altair 8800, custom machine controllers (8080 and Z-80), and a bunch of other crufty old things that I can barely even remember now.

Yeah, I'm that old. And just so you know, we really did walk 20 miles to school and back, and it was uphill both ways! And we didn't have your fancy ones and zeros back then. Why, I had to write an entire database with just zeros! Wimps! Learn to program using a soldering iron, ya slackers! Mutter, mutter, mumble...

Personal sandbox area

This is some code that I might post in the Bash FAQ or open questions pages, if I can determine that it's a good solution (or fix the problems, if I can find any). Do NOT trust this code -- it's just a draft.

Suppose you have multiple computers, only one of which operates your desktop environment, and you want the other machines to notify the desktop machine if something noteworthy happens. The definition of "noteworthy" doesn't matter to this example code, but it could be a disk which is getting dangerously full, or incoming mail that matches a certain pattern.

Here's some very simple Bash and Tcl code which demonstrates a basic framework that you could use to create such a system. It's based on the ability of Bash to use "/dev/tcp" as a way to easily send messages to TCP ports.

On the desktop machine, run this at a Bash prompt, or put the equivalent into a Tcl program:

proc respond {channel address port} {
  puts "$channel $address $port [gets $c]";
  close $c};
socket -server respond 8765;
vwait forever'

On the other machine(s), run this Bash program:

while sleep 3;
  do date > /dev/tcp/desktop.yourdomain.com/8765;

...where "desktop.yourdomain.com" is the name or I.P. address of your desktop machine.

If that fails, then don't bother making the programs any fancier until you figure out what's wrong. If your firewall is blocking the port, or the port is in use by another program, try some other port.

If it works, then every three seconds or so, you should see the current date appear on the server side. Now you can extend the programs to start some function whenever a particular condition is satisfied.

(Draft of a possible addition to BashFAQ #45)

Suppose you want the newest instance of a script to replace any existing instances of the same script. As before, if you find yourself in this position, you might want to reconsider your overall approach. There is no completely satisfactory way to enforce a single instance of a given script, because the system simply does not maintain an unchangeable link between a running process and the original contents & location of every file used when the process was created.

All the same, sometimes a buggy script has an unpleasant tendency to be hard to stop, or get stuck in certain rare circumstances, yet it's not enough of a problem to be worth tracking down and fixing properly. So, with caveats about unreliability in mind, here's one way to have new invocations replace existing ones:

(Addendum: after some testing, it's clear that this code does NOT work correctly, and is useful only as a fumbling step towards something better, or perhaps as a step towards proving that the whole approach is a bad idea. I have to confess that I still use it, not because it works correctly, but because it at least manages to give me some information about running processes that I've started. Maybe someday I'll come back to this code and fix it right. In the meantime, caveat coder.)

#!/usr/bin/env bash
# (Insert useful description of the program here)

# Issue a warning if it looks like this script is already running.
if (( $(pgrep -flU$(whoami) $0 | wc -l) > 1 )); then
   sleep 2 # Yes, this delay is ugly, but sometimes process startup...
   # ...briefly shows two instances, so pause a bit and double-check.
   if (( $(pgrep -flU$(whoami) $0 | wc -l) > 1 )); then
       echo "There may be an existing duplicate process running:"
       pgrep -flU$(whoami) $0
       echo "Consider running the following commands, as appropriate:"
       echo "  kill -1 "$(pgrep -fU$(whoami) $0|grep -v $$)
       echo "  pgrep -flU$(whoami) $0"
       echo "  kill -1 \$(pgrep -fU$(whoami) $0|grep -v $$)"
       echo "  (The process that was just started is: $$)"

# (Insert the the rest of the script below)

If you're feeling really, really bold, you could make the pkill automatic. If you're clever enough, however, to make sure that you never automatically pkill the wrong processes, then maybe you should apply your ample talents to avoiding the bugs which got you into that situation in the first place. As for me (WillDye), if I have to kill stale processes, I want to be reminded that there's a problem.


WillDye (last edited 2010-01-15 17:25:15 by WillDye)