zigford.org

About | Links | Scripts
Sharing linux/windows scripts and tips

Ip addresses on your subnet with xargs

September 01, 2018 — Jesse Harris

xargs strikes again. This time I'm going to use it's parallel feature to ping 255 machines very quickly. xargs has a parem -Px where x is the number of parallel processes to spawn of the subsequent process.


Update - 11/04/2019 Added MacOS Xargs syntax

Together with the bash {1..255} expression that expands to output 1 to 255, we can do something like this

        $ s=192.168.11.
        $ echo ${s}{1..254} | xargs -P254 -d' ' -L1 ping -c1 -w1 | grep 'bytes from'

In this example, -P254 tells xargs to spawn 254 procceses, -d' ' says to split commands with a space instead of the normal newline, and -L1 says to finish building the command after 1 amount of input.

To achieve the same result in powershell is not quite as simple. Out of the box you could use a ForeEach-Object loop like so:

        PS> $s='192.168.11.'
        PS> echo $s[1..254] | %{ Test-Connection $_ -Count 1 -TTL 1 -EA SilentlyContinue }

But it's just a sequential loop. Instead we are going to have to leverage the .Net ping class.

Lee Holmes shared this on twitter back in 2015:

Sweep a /16 in 30s:

          $t=$ips|%{
              (New-Object Net.NetworkInformation.Ping).SendPingAsync($_,250)};
              [Threading.Tasks.Task]::WaitAll($t);
              $t.Result

Before you run this, build out an array of ips, like so:

PS> $ips=[1..254] | %{"192.168.11.$_"}

This use of powershell seems a bit too obtuse for me, and not something likely to stick in my head.

I did find other ways to do it in powershell. A collegue of mine Darryl, dardie on github added this commit to a module I maintain which has pretty good results. Again however not something you could commit to memory as you need to write a function to use it.

Final thoughts

In this case it looks to me like bash wins, if not in performance, but by being simpler to implement and commit to memory, or recreate from memory. But if I ever need to do this in powershell again, I can just come back to my site for reference.

If you have any comments or feedback, please email me and let me know if you will allow your feedback to be posted here.

MacOS

For completeness and because I tried to run this and failed on MacOS today I'm adding it's syntax:

Xargs on MacOS is a BSD variant, seemlingly pulled from FreeBSD going by the man page. It still supports the -Px, however -d is not required as it splits on newline and spaces by default. The other difference is that instead of -L1 we use -n1 with essentially the same effect.

Also of note is the differences with ping. Rather than -w1 to reduce time waiting for a ping reply, -t1 is used.

        echo "192.168.11."{1..254} | xargs -P254 -n1 ping -c1 -t1 |
        awk '/bytes from/ {
            match($0,"[0-9]+.[0-9]+.[0-9]+.[0-9]+");
            n=substr($0,RSTART,RLENGTH);
            print n
        }'

In this example, I'm using an awk script to only print hosts that respond

Tags: bash-v-powershell, powershell, xargs, bash, ping, awk