在Bash脚本中并行使用Ping [英] Using Ping in Parallel in a Bash Script

查看:53
本文介绍了在Bash脚本中并行使用Ping的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我尝试在bash脚本中并行ping一系列地址,计算仍然存在的地址,然后打印出来.该脚本用于ping地址并打印实时地址,但始终输出:

So I'm trying to ping a range of addresses in parallel in a bash script, count the ones that are alive, and print them out. The script works to ping the addresses and print the live ones out but it always outputs:

有0个在线主机和254个脱机主机"

"There were 0 online hosts and 254 offline hosts"

这不是在我的代码中递增ALIVE变量,可能是因为它在子外壳中吗?我该如何解决?这是我现在所拥有的:

It's not incrementing the ALIVE variable in my code, maybe because it's in a subshell? How could I get around this? Here's what I have right now:

#!/bin/bash

TOTAL=0
ALIVE=0

if [ $# -eq 3 ]
then
    echo -n 'Live hosts:'
    for ((i = $2; i <= $3 && i <= 254; ++i))
    do
        ((++TOTAL))
        ping -c 1 -i 0.2 -w 1 -W 1 $1.$i > /dev/null && ((++ALIVE)) && echo "    $1.$i" &
    done

    echo "There were $ALIVE online hosts and $((($TOTAL - $ALIVE))) offline hosts"
else
    echo "USAGE: pingRange.sh <first 3 octets of ip> <last octet start> <last octet end>"
    echo "    Ex: pingRange.sh 192.168.0 1 254

注意:其他"部分显示了脚本的示例输入.

Note: An example input for the script is shown in the "else" part.

注2:是的,我知道nmap更容易,我已经用nmap编写了一个工作脚本,现在尝试做一个ping操作.

Note 2: Yes I know nmap is easier, I've already wrote a working script with nmap, trying to do one for ping now.

注3:我使用了一个临时文件,它可以正常工作,更新后的代码具有#NEW注释:

Note 3: I used a temporary file and it worked, updated code has #NEW comment:

#!/bin/bash

if [ $# -eq 3 ]
then
    TOTAL=0 #NEW
    TEMP=mktemp #NEW
    echo -n 'Live hosts:'
    for ((i = $2; i <= $3 && i <= 254; ++i))
    do
        ((++TOTAL))
        ping -c 1 -i 0.2 -w 1 -W 1 $1.$i > /dev/null && echo "    $1.$i" >> $TEMP & #NEW
    done
    wait #NEW
    cat $TEMP

    ALIVE=$(cat $TEMP | wc -l) #NEW
    echo "There were $ALIVE online hosts and $((($TOTAL - $ALIVE))) offline hosts"

    rm $TEMP #NEW
else
    echo "USAGE: pingRange.sh <first 3 octets of ip> <last octet start> <last octet end>"
    echo "    Ex: pingRange.sh 192.168.0 1 254

推荐答案

... && ((++ALIVE)) && ... &

此表达式在另一个进程内部运行,因此更改在父进程中不可见

This expression is run inside inside another process, so the changes are not visible in your parent process

a=1
((++a)) &    # <- is run as another process
echo "$a"  # this will print 1 ...

(
    ((++a))
    echo "$a"
) &          # this will print 2 in the background

wait

因此,我们要运行((($ 3-$ 2))进程.这些过程中的每一个都将同时运行.最后,我们需要从所有这些过程中获取输出.我们到达了所谓的同步".我们需要将所有流程中的所有值同步到一个点.
我们可以想象使用ex.255个文件,每个进程唯一一个文件.然后,在孩子执行完之后,我们可以查询文件.
最简单的方法是使用stdout或其他行缓冲流:

So, we want to run (( $3 - $2 )) processes. Each of these processes will be run concurrently. We need to get output from all these processes on the end. We arrive at what we call "synchronization". We need to synchronize all values from all the processes to one point.
We can imagine using ex. 255 files, one file unique for each process. Then after childs execute we can query the files.
The easiest is to use stdout or other line-buffered stream:

live_hosts=$(
   for ((i = $2; i <= $3 && i <= 254; ++i)); do
       # `if` is more readable then `a && b`
       (
          if ping -c 1 -i 0.2 -w 1 -W 1 "$1.$i" >/dev/null; then
              echo "$1.$i"
          fi
       ) &
   done
   wait  # remember to wait for all the childs
)

因为应该对stdout 行进行缓冲,所以多个 echo"$ 1. $ i" 不应截取该写操作,因此我们应该只得到一个带有行的变量.然后,您可以:

Because stdout should be line buffered, the multiple echo "$1.$i" shouldn't intercept the write, so we should arrive at just a variable with lines. Then you can just:

echo "There were $(printf "$live_hosts" | wc -l) online hosts"

但是我们可以使用一个临时目录来实现:

But we could do this with a temporary directory:

tmpdir=$(mktemp -d)

for ((i = $2; i <= $3 && i <= 254; ++i)); do
   (
      if ping -c 1 -i 0.2 -w 1 -W 1 "$1.$i" >/dev/null; then
           # create a file with the name "$i" inside tmpdir
           # I don't think content matters (just the name of file)
           touch "$tmpdir"/"$i"
       fi 
    ) &
done
wait

# ex. the count of alives are the count of files inside out tmpdir
alive=$(find "$tmpdir" -type f -print . | wc -c)

# this is funny
for i in "$tmpdir"/*; do
      echo "$1.$i is alive!"
done

# remember to cleanup
rm -r "$tmpdir"

为了使它有趣,并且因为我们喜欢oneliners,这是使用 xargs seq 的解决方案:

And just to make it interesting and because we love oneliners, here's a solution using xargs and seq:

live_hosts=$(seq -f "$1.%.0f" "$2" "$3" | xargs -n1 -P0 -- sh -c 'ping -c 1 -i 0.2 -w 1 -W 1 "$1" >/dev/null && echo "$1"' --)
alive=$(echo "$live_hosts" | wc -l)
# well, if just the count matters, add the `| wc -l` to the one liner ..

这篇关于在Bash脚本中并行使用Ping的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆