In the previous column on hacking PingPlotter I discussed how you can use the tool's Web interface and the curl utility to add targets to be tracked, for example, to add a single host you would enter the following on the command line:

curl ' \&target='

Moreover, a whole range of hosts can be added using sequences; for example:

curl ' ID=NEWTARGET \&target=192.168.[1-254].[1-254]'

But, as I pondered at the end of the previous column, how could you add only the active hosts on your network? After a bit of tinkering this is the Bash script I came up with:

#!/bin/bash# (the previous "hash bang" line isn't necessary under OS X)## Usage: pp-prog %1 %2 %3 %4 %5##       %1 - first IP address octet#       %2 - second IP address octet#       %3 - third IP address octet#       %4 - start value for fourth IP address octet#       %5 - end value for fourth IP address octet## Example: > 192 168 1 1 254#COUNT=3    # number of pings to send to each hostDOT="."    # separator for IP address#a=$1$DOT$2$DOT$3$DOT  # build a string of the top # three IP address octetsfor (( i=$4; i<=$5; i++ )) # note 1  do    response=$(ping -t 1 -c $COUNT $a$i | grep 'received' | awk -F',' '{ print $2 }' | awk '{ print $1 }')  # notes 2, 3, 4, 5    if [ $response -ne 0 ];      then        printf "Host : $a$i is up at $(date)  \r" # note 6a        curl ' \ &target='$a$i &>/dev/null  #note 6b else        printf "Host : $a$i is down at $(date)\r"  # note 7    fi  doneprintf "%0.s " {1..62} # note 8aprintf "\rDone.\n" # note 8b

If you're on OS X and have curl installed (see the previous column) then you can just create a file called with the above text (modified for the address of your PingPlotter host then make it executable with the command:

chmod +x

Voila! You can now configure PingPlotter for only the active hosts on your network. Note that if you run the script again PingPlotter will add a second entry for each host the script finds which is not what you want ... 

If you have a better script or even one that can run repeatedly and add newly found hosts without duplicating those already added as targets to PingPlotter or even remove hosts that go missing let me know.


First of all, if you're on Windows and you don't have the Bash shell see Is there a way to run Bash scripts on Windows?

Next, here are a few notes on what the script is doing:

Note 1: This is a C-style for-loop which is easier to use with variables, in this case, $4 and $5, the start and end of the Class C network defined by $1, $2, and $3 

Note 2: For OS X's ping tool  in the command:

ping -t 1 -c $COUNT $a$i

... the "-t 1" specifies a 1 second timeout "before ping exits regardless of how many packets have been received." For other systems' ping utility the correct switch is usually -W. The output from a successful ping as above will look something like:

PING ( 56 data bytes64 bytes from icmp_seq=0 ttl=64 time=0.626 ms--- ping statistics ---2 packets transmitted, 1 packets received, 50.0% packet lossround-trip min/avg/max/stddev = 0.626/0.626/0.626/0.000 ms

A failed ping will look like:

PING ( 56 data bytes--- ping statistics ---1 packets transmitted, 0 packets received, 100.0% packet loss 

Note 3: The output from ping is piped to grep and the argument 'received' tells grep to send any line containing that string to stdout. For the successful ping example in note 1 the output from grep would be just the line:

2 packets transmitted, 1 packets received, 50.0% packet loss

The failed ping will produce:

2 packets transmitted, 0 packets received, 100.0% packet loss

Note 4: The output from grep is piped to the awk utility. The -F switch specifies the separator that divides the data items, in this case commas and the { print $2 } argument specifies to output the second field thus, from grep's output of the successful ping awk would, in turn, output:

 1 packets received

This could also be 2 or 3 packets depending on how many were received during the time set by ping's -t switch. Obviously a failed ping would result in awk outputting:

 0 packets received

The awk output is sent to a second invocation of awk which assume that a space is a separator and is instructed to print the first field which will be either 0 for ping failed or 1,2, or 3 for ping succeeded.

Note 5: The $ in front of the parentheses around the ping, grep, and awk commands converts the value produced by the ping-grep-awk-awk commands into a value that can be stored in the variable response. 

Note 6a: If the variable response does not equal "0" (i.e. one or more packets received) then print, using printf, a success status update (note the carriage return, \r). This will update look like:

Host : is down at Wed Jul 23 16:50:09 PDT 2014

Note 6b: ... then invoke curl and send the command to PingPlotter to add a target specified by combination of variables $a$i (the variables' current values are substituted for the placeholders). After the curl command is:


... which sends both output from the command via standard output (stdout) as well as error output to the bit bucket. If you really care about errors then feel free to modify this but for successful invocations of curl you'll still want to get rid of the stdout output; it will just be a block of XML like this:

<?xml version="1.0" encoding="ISO-8859-1"?><PingPlotter/>

Note 7: If the variable response equals "0" then print an failure update:

Host : is down at Wed Jul 23 16:50:09 PDT 2014 

Using printf with a "\r" appends a carriage return so that further ping failure updates  will overwrite the line. This overwriting will occur until a successful update overwrites the line and then moves printing to the next line down. Note the two spaces before the \r in the success update covered in note 6a; those will overwrite the last two characters of the failure message which is due to "down" being longer than "up". Why all of this faffing about? 'Cause the updates let you know something is happening even when there's a whole run of ping failures and it might as well look pretty.

Note 8a & 8b: Finally, when we've looped through all of the IP address space we print 62 spaces to overwrite the last status message The printf that outputs the spaces is a little tricky; "%0.s " specifies to print a zero-length string with no extra characters if the string provided is longer than zero. Then after this zero-length string print a space and there are 62 arguments, so printf prints 62 zero-length strings following each with a space. The final printf prints a carriage return, the text "Done.", and finally a newline before exiting the script. Again, pretty is as pretty does.