如何编写一个 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:11:55  来源:igfitidea点击:

How can I write a Linux bash script that tells me which computers are ON in my LAN?

linuxbashping

提问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 dir1and dir2, each containing sub1and sub2)

(它也适用于诸如mkdir {dir1,dir2}/{sub1,sub2}- 生成dir1and 之类的东西dir2,每个都包含sub1and 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 1will 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 -tflag. 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 stdoutto /dev/nullwith 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 downmessages), 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, nmapis 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 fpingin 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