Search code examples
shellpingstderrapplescript-objc

cocoa-applescript - background process shell command


I have built a program which involves pinging specified IP addresses to tell whether they are active or not.

repeat for IPaddress in allIPaddresses
try
    do shell script "ping -o -t 1 -c 1 " & IPaddress
    set goodIPs to (goodIPs & IPaddress) -- where goodIPs is a list of online IPs
end try
end repeat

The problem is that it will cycle through a lot of IPs if needed and the interface freezes up while it is pinging - so if you needed to hit the "Quit" button, you can't and Force Quitting is the only way to stop it. After searching around for how to run the command as a background process, I found the most common answer (eg https://discussions.apple.com/thread/323661?start=0&tstart=0) was to add:

> /dev/null 2>&1 &

or slight (but similar output) variations of that to the end of the shell command. But that involves sending the stderr away from the application, and since my program needs the stderr to tell if the ping was successful or not, this is not an option. Does anyone know how to keep stderr normal but move the command to a background process so that the interface works as normal?


Solution

  • Updated Answer

    If you want to ping one at a time no matter how slow and show off the slow progress with a progress bar ;-)

    ping -o -t 1 -c 1 192.168.0.1 > /dev/null 2>&1 && echo up
    

    This will output up if the host is up, and nothing if it is down. Or if you want it to output down if the host is down:

    ping -o -t 1 -c 1 192.168.0.1 > /dev/null 2>&1 && echo up || echo down
    

    Second Answer

    You could do it in the shell with a little script like this. Save it as pinger, and then make it executable with

    chmod +x pinger
    

    Then in your Applescript, you would need to write the list of IP addresses you want checked into a file called iplist.txt and use

    do shell script /path/to/wherever/pinger
    

    and grab its output.

    You can try it in the Terminal with

    ./pinger
    

    Here is the script.

    #!/bin/bash
    # pinger
    #
    # Remove results of any previous runs, but suppress any error messages
    rm hostup-* 2> /dev/null
    
    # Ping all hosts in "iplist.txt" ...
    # ... and create file "hostup-<IP ADDRESS>" for any that are up
    while read ip; do
       ( ping -o -t 1 -c 1 $ip > /dev/null 2>&1 && touch hostup-$ip ) &
    done < iplist.txt
    
    wait # for all pings to finish
    
    # Now go back through and see who answered
    while read ip; do
       filename="hostup-$ip"
       if [ -f "$filename" ]; then
          rm $filename
          echo $ip
       fi
    done < iplist.txt
    

    Précis of Original Answer

    Use GNU Parallel...