在 Bash 脚本中并行使用 Ping
Using Ping in Parallel in a Bash Script
所以我尝试在 bash 脚本中并行 ping 一系列地址,计算存活的地址,并将它们打印出来。该脚本用于 ping 地址并打印出实时地址,但它始终输出:
"There were 0 online hosts and 254 offline hosts"
它没有在我的代码中递增 ALIVE 变量,可能是因为它在子 shell 中?我怎么能解决这个问题?这是我现在拥有的:
#!/bin/bash
TOTAL=0
ALIVE=0
if [ $# -eq 3 ]
then
echo -n 'Live hosts:'
for ((i = ; i <= && i <= 254; ++i))
do
((++TOTAL))
ping -c 1 -i 0.2 -w 1 -W 1 .$i > /dev/null && ((++ALIVE)) && echo " .$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
注意:脚本的示例输入显示在 "else" 部分。
注意 2:是的,我知道 nmap 更简单,我已经用 nmap 编写了一个工作脚本,现在尝试为 ping 做一个。
注意 3:我使用了一个临时文件并且它有效,更新后的代码有#NEW 注释:
#!/bin/bash
if [ $# -eq 3 ]
then
TOTAL=0 #NEW
TEMP=mktemp #NEW
echo -n 'Live hosts:'
for ((i = ; i <= && i <= 254; ++i))
do
((++TOTAL))
ping -c 1 -i 0.2 -w 1 -W 1 .$i > /dev/null && echo " .$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)) && ... &
此表达式 运行 在另一个进程中,因此更改在您的父进程中不可见
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
所以,我们要 运行 (( - ))
进程。这些进程中的每一个都将 运行 同时进行。我们最终需要从所有这些过程中获得输出。我们到达了我们所说的 "synchronization"。我们需要将所有进程的所有值同步到一个点。
我们可以想象使用 ex。 255 个文件,每个进程一个文件唯一。然后在 childs 执行后我们可以查询文件。
最简单的是使用标准输出或其他行缓冲流:
live_hosts=$(
for ((i = ; i <= && i <= 254; ++i)); do
# `if` is more readable then `a && b`
(
if ping -c 1 -i 0.2 -w 1 -W 1 ".$i" >/dev/null; then
echo ".$i"
fi
) &
done
wait # remember to wait for all the childs
)
因为 stdout 应该 行缓冲,多个 echo ".$i"
不应该拦截写入,所以我们应该只得到一个带有行的变量。那么你可以:
echo "There were $(printf "$live_hosts" | wc -l) online hosts"
但是我们可以用一个临时目录来做到这一点:
tmpdir=$(mktemp -d)
for ((i = ; i <= && i <= 254; ++i)); do
(
if ping -c 1 -i 0.2 -w 1 -W 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 ".$i is alive!"
done
# remember to cleanup
rm -r "$tmpdir"
只是为了让它变得有趣,因为我们喜欢单线,这里有一个使用 xargs
和 seq
的解决方案:
live_hosts=$(seq -f ".%.0f" "" "" | xargs -n1 -P0 -- sh -c 'ping -c 1 -i 0.2 -w 1 -W 1 "" >/dev/null && echo ""' --)
alive=$(echo "$live_hosts" | wc -l)
# well, if just the count matters, add the `| wc -l` to the one liner ..
我相信您只需使用 wait
即可做到这一点。
正在修改您的代码,例如(未测试):
#!/bin/bash
TOTAL=0
ALIVE=0
if [ $# -eq 3 ]
then
unset pids
declare -A pids
echo -n 'Live hosts:'
for ((i = ; i <= && i <= 254; ++i))
do
((++TOTAL))
ping -c 1 -i 0.2 -w 1 -W 1 .$i > /dev/null &
pids[$i]=$!
done
for i in "${!pids[@]}"
do
wait ${pids[$i]} && ((++ALIVE)) && echo " .$i"
done
echo "There were $ALIVE online hosts and $((($TOTAL - $ALIVE))) offline hosts"
else
# ...
unset
/ declare
- 为了安全起见
ping ... &
仍然在后台运行命令
pids[$i]=$!
保存其 pid
for ...
遍历键
wait ${pids[$i]}
returnscmd完成后的退出状态
&& ...
和之前一样
使用 GNU Parallel 看起来像这样:
pingrange() {
three=
start=
end=
total=$(($end-$start))
online="$(seq $start $end |
parallel -j0 "ping -c 1 -i 0.2 -w 1 -W 1 $three.{} > /dev/null && echo ' $three.{}'")"
alive=$(echo "$online" | wc -l)
offline=$((total-alive))
echo "$online"
echo "There were $alive online hosts and $offline offline hosts"
}
它 运行 是正确的,即使您的系统不能同时 运行 所有 ping
s(例如,如果您的进程 table 接近满) .
或者您可以直接使用:
fping -g $three.$start $three.$end
并处理输出。有关更多选项,请参阅 man fping。
所以我尝试在 bash 脚本中并行 ping 一系列地址,计算存活的地址,并将它们打印出来。该脚本用于 ping 地址并打印出实时地址,但它始终输出:
"There were 0 online hosts and 254 offline hosts"
它没有在我的代码中递增 ALIVE 变量,可能是因为它在子 shell 中?我怎么能解决这个问题?这是我现在拥有的:
#!/bin/bash
TOTAL=0
ALIVE=0
if [ $# -eq 3 ]
then
echo -n 'Live hosts:'
for ((i = ; i <= && i <= 254; ++i))
do
((++TOTAL))
ping -c 1 -i 0.2 -w 1 -W 1 .$i > /dev/null && ((++ALIVE)) && echo " .$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
注意:脚本的示例输入显示在 "else" 部分。
注意 2:是的,我知道 nmap 更简单,我已经用 nmap 编写了一个工作脚本,现在尝试为 ping 做一个。
注意 3:我使用了一个临时文件并且它有效,更新后的代码有#NEW 注释:
#!/bin/bash
if [ $# -eq 3 ]
then
TOTAL=0 #NEW
TEMP=mktemp #NEW
echo -n 'Live hosts:'
for ((i = ; i <= && i <= 254; ++i))
do
((++TOTAL))
ping -c 1 -i 0.2 -w 1 -W 1 .$i > /dev/null && echo " .$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)) && ... &
此表达式 运行 在另一个进程中,因此更改在您的父进程中不可见
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
所以,我们要 运行 (( - ))
进程。这些进程中的每一个都将 运行 同时进行。我们最终需要从所有这些过程中获得输出。我们到达了我们所说的 "synchronization"。我们需要将所有进程的所有值同步到一个点。
我们可以想象使用 ex。 255 个文件,每个进程一个文件唯一。然后在 childs 执行后我们可以查询文件。
最简单的是使用标准输出或其他行缓冲流:
live_hosts=$(
for ((i = ; i <= && i <= 254; ++i)); do
# `if` is more readable then `a && b`
(
if ping -c 1 -i 0.2 -w 1 -W 1 ".$i" >/dev/null; then
echo ".$i"
fi
) &
done
wait # remember to wait for all the childs
)
因为 stdout 应该 行缓冲,多个 echo ".$i"
不应该拦截写入,所以我们应该只得到一个带有行的变量。那么你可以:
echo "There were $(printf "$live_hosts" | wc -l) online hosts"
但是我们可以用一个临时目录来做到这一点:
tmpdir=$(mktemp -d)
for ((i = ; i <= && i <= 254; ++i)); do
(
if ping -c 1 -i 0.2 -w 1 -W 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 ".$i is alive!"
done
# remember to cleanup
rm -r "$tmpdir"
只是为了让它变得有趣,因为我们喜欢单线,这里有一个使用 xargs
和 seq
的解决方案:
live_hosts=$(seq -f ".%.0f" "" "" | xargs -n1 -P0 -- sh -c 'ping -c 1 -i 0.2 -w 1 -W 1 "" >/dev/null && echo ""' --)
alive=$(echo "$live_hosts" | wc -l)
# well, if just the count matters, add the `| wc -l` to the one liner ..
我相信您只需使用 wait
即可做到这一点。
正在修改您的代码,例如(未测试):
#!/bin/bash
TOTAL=0
ALIVE=0
if [ $# -eq 3 ]
then
unset pids
declare -A pids
echo -n 'Live hosts:'
for ((i = ; i <= && i <= 254; ++i))
do
((++TOTAL))
ping -c 1 -i 0.2 -w 1 -W 1 .$i > /dev/null &
pids[$i]=$!
done
for i in "${!pids[@]}"
do
wait ${pids[$i]} && ((++ALIVE)) && echo " .$i"
done
echo "There were $ALIVE online hosts and $((($TOTAL - $ALIVE))) offline hosts"
else
# ...
unset
/declare
- 为了安全起见ping ... &
仍然在后台运行命令pids[$i]=$!
保存其 pidfor ...
遍历键wait ${pids[$i]}
returnscmd完成后的退出状态&& ...
和之前一样
使用 GNU Parallel 看起来像这样:
pingrange() {
three=
start=
end=
total=$(($end-$start))
online="$(seq $start $end |
parallel -j0 "ping -c 1 -i 0.2 -w 1 -W 1 $three.{} > /dev/null && echo ' $three.{}'")"
alive=$(echo "$online" | wc -l)
offline=$((total-alive))
echo "$online"
echo "There were $alive online hosts and $offline offline hosts"
}
它 运行 是正确的,即使您的系统不能同时 运行 所有 ping
s(例如,如果您的进程 table 接近满) .
或者您可以直接使用:
fping -g $three.$start $three.$end
并处理输出。有关更多选项,请参阅 man fping。