如何编写一个 Linux bash 脚本来告诉我 LAN 中哪些计算机正在运行?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/733418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I write a Linux bash script that tells me which computers are ON in my LAN?
提问by Dumb Questioner
How can I write a Linux Bash script that tells me which computers are ON in my LAN?
如何编写一个 Linux Bash 脚本来告诉我 LAN 中哪些计算机正在运行?
It would help if I could give it a range of IP addresses as input.
如果我可以给它一个 IP 地址范围作为输入,那会有所帮助。
采纳答案by dbr
I would suggest using nmap's ping-scan flag,
我建议使用 nmap 的 ping-scan 标志,
$ nmap -sn 192.168.1.60-70
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2009-04-09 20:13 BST
Host machine1.home (192.168.1.64) appears to be up.
Host machine2.home (192.168.1.65) appears to be up.
Nmap finished: 11 IP addresses (2 hosts up) scanned in 0.235 seconds
That said, if you want to write it yourself (which is fair enough), this is how I would do it:
也就是说,如果你想自己写(这很公平),我会这样做:
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
..and an explanation of each bit of the above command:
..以及对上述命令的每一位的解释:
Generating list of IP addresses
生成 IP 地址列表
You can use the {1..10}
syntax to generate a list of numbers, for example..
您可以使用{1..10}
语法生成数字列表,例如..
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
(it's also useful for things like mkdir {dir1,dir2}/{sub1,sub2}
- which makes dir1
and dir2
, each containing sub1
and sub2
)
(它也适用于诸如mkdir {dir1,dir2}/{sub1,sub2}
- 生成dir1
and 之类的东西dir2
,每个都包含sub1
and sub2
)
So, to generate a list of IP's, we'd do something like
因此,要生成 IP 列表,我们会执行类似的操作
$ echo 192.168.1.{1..10}
192.168.1.1 192.168.1.2 [...] 192.168.1.10
Loops
循环
To loop over something in bash, you use for
:
要在 bash 中循环某些内容,您可以使用for
:
$ for thingy in 1 2 3; do echo $thingy; done
1
2
3
Pinging
平安
Next, to ping.. The ping command varies a bit with different operating-systems, different distributions/versions (I'm using OS X currently)
接下来,要 ping .. ping 命令因不同的操作系统、不同的发行版/版本而有所不同(我目前使用的是 OS X)
By default (again, on the OS X version of ping
) it will ping until interrupted, which isn't going to work for this, so ping -c 1
will only try sending one packet, which should be enough to determine if a machine is up.
默认情况下(同样,在 的 OS X 版本上ping
)它会一直 ping 直到中断,这对此不起作用,因此ping -c 1
只会尝试发送一个数据包,这应该足以确定机器是否已启动。
Another problem is the timeout value, which seems to be 11 seconds on this version of ping.. It's changed using the -t
flag. One second should be enough to see if a machine on the local network is alive or not.
另一个问题是超时值,在此版本的 ping 上似乎是 11 秒。它已使用-t
标志更改。一秒钟应该足以查看本地网络上的机器是否处于活动状态。
So, the ping command we'll use is..
所以,我们将使用的 ping 命令是..
$ ping -c 1 -t 1 192.168.1.1
PING 192.168.1.1 (192.168.1.1): 56 data bytes
--- 192.168.1.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
Checking ping result
检查ping结果
Next, we need to know if the machine replied or not..
接下来,我们需要知道机器是否回复了..
We can use the &&
operator to run a command if the first succeeds, for example:
&&
如果第一个成功,我们可以使用运算符来运行命令,例如:
$ echo && echo "It works"
It works
$ nonexistantcommand && echo "This should not echo"
-bash: nonexistantcommand: command not found
Good, so we can do..
很好,所以我们可以做..
ping -c 1 -t 1 192.168.1.1 && echo "192.168.1.1 is up!"
ping -c 1 -t 1 192.168.1.1 && echo "192.168.1.1 上线了!"
The other way would be to use the exit code from ping.. The ping command will exit with exit-code 0 (success) if it worked, and a non-zero code if it failed. In bash you get the last commands exit code with the variable $?
另一种方法是使用 ping 的退出代码。如果它工作,ping 命令将以退出代码 0(成功)退出,如果失败则以非零代码退出。在 bash 中,您使用变量获得最后一个命令退出代码$?
So, to check if the command worked, we'd do..
所以,要检查命令是否有效,我们会做..
ping -c 1 -t 1 192.168.1.1;
if [ $? -eq 0 ]; then
echo "192.168.1.1 is up";
else
echo "ip is down";
fi
Hiding ping output
隐藏ping输出
Last thing, we don't need to see the ping output, so we can redirect stdout
to /dev/null
with the >
redirection, for example:
最后一件事,我们不需要看平输出,所以我们可以重定向stdout
到/dev/null
与>
重定向,例如:
$ ping -c 1 -t 1 192.168.1.1 > /dev/null && echo "IP is up"
IP is up
And to redirect stderr
(to discard the ping: sendto: Host is down
messages), you use 2>
- for example:
并重定向stderr
(丢弃ping: sendto: Host is down
消息),您使用2>
- 例如:
$ errorcausingcommand
-bash: errorcausingcommand: command not found
$ errorcausingcommand 2> /dev/null
$
The script
剧本
So, to combine all that..
所以,把所有这些结合起来..
for ip in 192.168.1.{1..10}; do # for loop and the {} operator
ping -c 1 -t 1 192.168.1.1 > /dev/null 2> /dev/null # ping and discard output
if [ $? -eq 0 ]; then # check the exit code
echo "${ip} is up" # display the output
# you could send this to a log file by using the >>pinglog.txt redirect
else
echo "${ip} is down"
fi
done
Or, using the &&
method, in a one-liner:
或者,使用该&&
方法,在单行中:
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
Problem
问题
It's slow.. Each ping command takes about 1 second (since we set the -t timeout flag to 1 second). It can only run one ping command at a time.. The obvious way around this is to use threads, so you can run concurrent commands, but that's beyond what you should use bash for..
它很慢.. 每个 ping 命令大约需要 1 秒(因为我们将 -t 超时标志设置为 1 秒)。它一次只能运行一个 ping 命令。 解决这个问题的明显方法是使用线程,因此您可以运行并发命令,但这超出了您应该使用 bash 的范围。
"Python threads - a first example"explains how to use the Python threading module to write a multi-threaded ping'er.. Although at that point, I would once again suggest using nmap -sn
..
“Python 线程 - 第一个示例”解释了如何使用 Python 线程模块编写多线程 ping'er .. 虽然在这一点上,我再次建议使用nmap -sn
..
回答by Vatine
If you're limiting yourself to only having the last octet changing, this script should do it. It should be fairly obvious how to extend it from one to multiple octets.
如果您将自己限制为仅更改最后一个八位字节,则此脚本应该可以。如何将它从一个扩展到多个八位字节应该是相当明显的。
#! /bin/bash BASE= START= END= counter=$START while [ $counter -le $END ] do ip=$BASE.$counter if ping -qc 2 $ip then echo "$ip responds" fi counter=$(( $counter + 1 )) done
回答by chburd
Assuming my network is 10.10.0.0/24, if i run a ping on the broadcast address like
假设我的网络是 10.10.0.0/24,如果我在广播地址上运行 ping 就像
ping -b 10.10.0.255
I'll get an answer from all computers on this network that did not block their ICMP ping port.
我将从该网络上所有未阻止其 ICMP ping 端口的计算机上得到答复。
64 bytes from 10.10.0.6: icmp_seq=1 ttl=64 time=0.000 ms
64 bytes from 10.10.0.12: icmp_seq=1 ttl=64 time=0.000 ms
64 bytes from 10.10.0.71: icmp_seq=1 ttl=255 time=0.000 ms
So you just have to extract the 4th column, with awk for example:
所以你只需要提取第 4 列,例如使用 awk:
ping -b 10.10.0.255 | grep 'bytes from' | awk '{ print }'
10.10.0.12:
10.10.0.6:
10.10.0.71:
10.10.0.95:
Well, you will get duplicate, and you may need to remove the ':'.
好吧,你会得到重复的,你可能需要删除“:”。
EDIT from comments : the -c option limits the number of pings since the script will end, we can also limit ourself on unique IPs
从评论中编辑: -c 选项限制了 ping 次数,因为脚本将结束,我们也可以限制自己的唯一 IP
ping -c 5 -b 10.10.0.255 | grep 'bytes from' | awk '{ print }' | sort | uniq
回答by Tiberiu Ana
In the real world, you could use nmapto get what you want.
在现实世界中,您可以使用nmap来获得您想要的东西。
nmap -sn 10.1.1.1-255
This will ping all the addresses in the range 10.1.1.1 to 10.1.1.255 and let you know which ones answer.
这将 ping 10.1.1.1 到 10.1.1.255 范围内的所有地址,并让您知道哪些地址已回答。
Of course, if you in fact want to do this as a bash exercise, you could run ping for each address and parse the output, but that's a whole other story.
当然,如果您实际上想将其作为 bash 练习来执行,您可以对每个地址运行 ping 并解析输出,但这是另一回事。
回答by Can Berk Güder
Also using the "ping the broadcast address" method pointed out by chburd, this pipe should do the trick for you:
同样使用 chburd 指出的“ping 广播地址”方法,这个管道应该可以为您解决问题:
ping -c 5 -b 10.11.255.255 | sed -n 's/.* \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\).*//p' | sort | uniq
Of course, you'd have to change the broadcast address to that of your network.
当然,您必须将广播地址更改为您网络的广播地址。
回答by Eddy
Just for fun, here's an alternate
只是为了好玩,这是一个替代品
#!/bin/bash
nmap -sP 192.168.1.0/24 > /dev/null 2>&1 && arp -an | grep -v incomplete | awk '{print}' | sed -e s,\(,, | sed -e s,\),,
#!/bin/bash
nmap -sP 192.168.1.0/24 > /dev/null 2>&1 && arp -an | grep -v incomplete | awk '{print}' | sed -e s,\(,, | sed -e s,\),,
回答by Don Werve
As other posters pointed out, nmap
is the way to go, but here's how to do the equivalent of a ping scan in bash. I wouldn't use the broadcast ping, as a lot of systems are configured not to respond to broadcast ICMP nowadays.
正如其他海报指出的那样,这nmap
是要走的路,但这里是如何在 bash 中进行 ping 扫描的等效方法。我不会使用广播 ping,因为现在很多系统都配置为不响应广播 ICMP。
for i in $(seq 1 254); do
host="192.168.100.$i"
ping -c 1 -W 1 $host &> /dev/null
echo -n "Host $host is "
test $? -eq 0 && echo "up" || echo "down"
done
回答by d0k
There is also fping:
还有fping:
fping -g 192.168.1.0/24
or:
或者:
fping -g 192.168.1.0 192.168.1.255
or show only hosts that are alive:
或仅显示存活的主机:
fping -ag 192.168.1.0/24
It pings hosts in parallel so the scan is very fast. I don't know a distribution which includes fping
in its default installation but in most distributions you can get it through the package manager.
它并行 ping 主机,因此扫描速度非常快。我不知道fping
默认安装中包含的发行版,但在大多数发行版中,您可以通过包管理器获取它。
回答by erik
#!/bin/bash
for ((n=0 ; n < 30 ; n+=1))
do
ip=10.1.1.$n
if ping -c 1 -w 1 $ip > /dev/null 2> /dev/null >> /etc/logping.txt; then
echo "${ip} is up" # output up
# sintax >> /etc/logping.txt log with .txt format
else
echo "${ip} is down" # output down
fi
done