如何使用bash测试Internet连接?

142

如何在不ping网站的情况下测试网络连接?我的意思是,如果网站宕机了,但是有连接怎么办?有没有检查与世界连接的方法?


2
ping几个不同的网站? - anon
1
但我不想ping网站,还有其他选项吗? - lauriys
6
我只是想看看是否还有其他的方法! - lauriys
2
没有比向一组地址发送和接收单个数据包更好的方法,这些地址您知道不会同时离线。另一种方法是检查您当前设置的DNS,如果您不希望应用程序ping一个更公共的域名。 - Tamara Wijsman
@Neil:我不知道提问者的原因,但有些地方会屏蔽ping。例如,在我的工作场所,我无法ping到子网外的任何东西。 - PTBNL
14
我想知道是否有人在听,而不发出任何声音! - Kaz
22个回答

4
这个 Bash 脚本会连续检查互联网连接并在互联网可用时发出哔哔声。
#!/bin/bash
play -n synth 0.3 sine 800 vol 0.75
while :
do
pingtime=$(ping -w 1 8.8.8.8 | grep ttl)
if [ "$pingtime" = "" ] 
then 
   pingtimetwo=$(ping -w 1 www.google.com | grep ttl) 
   if [ "$pingtimetwo" = "" ] 
   then 
       clear ; echo 'Offline'
   else
       clear ; echo 'Online' ; play -n synth 0.3 sine 800 vol 0.75
   fi 
else
    clear ; echo 'Online' ; play -n synth 0.3 sine 800 vol 0.75
fi
sleep 1
done

4

如果你的本地域名服务器出现故障,

ping 4.2.2.1

是一个易于记忆且始终可用的IP地址(实际上它就是一个域名服务器)。


5
请执行命令 "ping 8.8.8.8",这是针对 Google 的域名服务器的测试。 - user3439968

4
@Jesse的回答类似,此选项可能比使用ping的任何解决方案快得多,也许比@Jesse的回答稍微更有效。

find /sys/class/net/ -maxdepth 1 -mindepth 1 ! -name "*lo*" -exec sh -c 'cat "$0"/carrier 2>&1' {} \; | grep -q '1'

解释:

该命令使用find-exec/sys/class/net/中运行命令,针对所有未命名为*lo*的文件。这些应该是包含有关您机器上可用网络接口信息的目录链接。

正在执行的命令是一个sh命令,它检查这些目录中carrier文件的内容。变量$interface/carrier的值有3个含义- 引用:

看起来有三种状态:

  • ./carrier不可读(例如当接口在Network Manager中被禁用时)。
  • ./carrier包含“1”(当接口已激活且连接到WiFi网络时)
  • ./carrier包含“0”(当接口已激活但未连接到WiFi网络时)

第一个选项在@Jesse's answer中没有处理。要去除的sh命令如下:

# Note: $0 == $interface
cat "$0"/carrier 2>&1

cat被用于检查carrier的内容,并将所有输出重定向到标准输出,即使它因为文件不可读而失败。 如果grep -q在这些文件中找到"1",则表示至少有1个接口已连接。 grep -q的退出代码将是最终退出代码。

用法

例如,使用此命令的退出状态,您可以在~/.xprofile中仅在有互联网连接时启动gnubiff

online() {
    find /sys/class/net/ -maxdepth 1 -mindepth 1 ! -name "*lo*" -exec sh -c 'cat "$0"/carrier 2>&1 > /dev/null | grep -q "1" && exit 0' {} \;
}
online && gnubiff --systemtray --noconfigure &

参考资料


3

最短的方式:fping 4.2.2.1 => "4.2.2.1 存活着"

我更喜欢这种方法,因为它比ping更快,输出更少,但不足之处是你需要安装它。

你可以使用任何公共 DNS,而不是特定的网站。

fping -q google.com && echo "做一些事情,因为你已经联网了!"

-q返回一个退出代码,所以我只是展示了一个在线运行的例子。

在Mac上安装:brew install fping;在Ubuntu上:sudo apt-get install fping


2
检查谷歌的索引页面是另一种方法:
#!/bin/bash

WGET="/usr/bin/wget"

$WGET -q --tries=20 --timeout=10 http://www.google.com -O /tmp/google.idx &> /dev/null
if [ ! -s /tmp/google.idx ]
then
    echo "Not Connected..!"
else
    echo "Connected..!"
fi

2

Ping的设计目的就是为了实现您想要的功能。但是,如果该网站阻止了ICMP回显,则可以通过telnet到某个站点的80端口、wget或curl来进行测试。


2

为了获得最快的结果,ping一下DNS服务器

ping -c1 "8.8.8.8" &>"/dev/null"

if [[ "${?}" -ne 0 ]]; then
    echo "offline"
elif [[ "${#args[@]}" -eq 0 ]]; then
    echo "online"
fi

可作为一个独立命令使用:linkStatus


1
如果您的目标是实际检查互联网连接,那么这个问题的现有答案中有很多缺陷。以下是您应该知道的几件事情:
  1. 您的计算机可能连接到一个没有互联网访问权限的网络
  2. 某个服务器可能宕机,但整个互联网仍然可用
  3. 即使您没有互联网访问权限,也有可能捕获门户为任意URL返回HTTP响应

考虑到这些问题,我认为最好的策略是通过HTTPS连接联系几个站点,并在其中任何一个站点响应时返回true。

例如:

connected_to_internet() {
  test_urls="\
  https://www.google.com/ \
  https://www.microsoft.com/ \
  https://www.cloudflare.com/ \
  "

  processes="0"
  pids=""

  for test_url in $test_urls; do
    curl --silent --head "$test_url" > /dev/null &
    pids="$pids $!"
    processes=$(($processes + 1))
  done

  while [ $processes -gt 0 ]; do
    for pid in $pids; do
      if ! ps | grep "^[[:blank:]]*$pid[[:blank:]]" > /dev/null; then
        # Process no longer running
        processes=$(($processes - 1))
        pids=$(echo "$pids" | sed --regexp-extended "s/(^| )$pid($| )/ /g")

        if wait $pid; then
          # Success! We have a connection to at least one public site, so the
          # internet is up. Ignore other exit statuses.
          kill -TERM $pids > /dev/null 2>&1 || true
          wait $pids
          return 0
        fi
      fi
    done
    # wait -n $pids # Better than sleep, but not supported on all systems
    sleep 0.1
  done

  return 1
}

使用方法:

if connected_to_internet; then
  echo "Connected to internet"
else
  echo "No internet connection"
fi

关于这种方法的一些注意事项:

  1. 它能够抵御我上面提到的所有误报和漏报
  2. 所有请求都并行进行,以最大化速度
  3. 如果您“技术上”拥有互联网访问权限但DNS不可用或网络设置出现问题,则会返回false,我认为在大多数情况下这是合理的

curl的返回代码没有被测试。在我的系统上,如果网络不可用,curl会给出rc=6(DNS解析失败),但是这个代码仍然报告“已连接到互联网”。 - ceperman
@ceperman curl的返回代码在if wait $pid;所在的行上进行测试。不知道为什么在您的系统上无法工作。您确定您正在使用bash吗? - Ajedi32
@ceperman 另一个可能性是:也许列表顶部的某个URL实际上对您返回成功,即使其他URL无法解析名称? - Ajedi32
2
我的bash基础比较薄弱,所以我查阅了关于wait的资料,现在明白返回代码确实被测试了。我重新复制了你的代码,今天它可以正常工作了——糟糕!上次我一定搞错了什么,虽然我不知道是什么或者怎么出错的。无论如何,我承认错误并道歉。 - ceperman

1

Pong并不表示服务器上的Web服务正在运行;它仅表示该服务器正在响应ICMP回显。 我建议使用curl并检查其返回值。


0

如果你想处理强制门户,你可以使用这个一行代码:

if [[ $(curl -s -D - http://www.gstatic.com/generate_204 2>/dev/null | head -1 | cut -d' ' -f 2) == "204" ]]; then
  echo 'online'
else
  echo 'offline'
fi

或者,如果您想要更易读的内容,可以区分被困住的门户和信号不足:

function is_online() {
  # Test signal
  local response
  response=$(curl --silent --dump-header - http://www.gstatic.com/generate_204 2> /dev/null)
  if (($? != 0)); then return 2; fi
  # Test captive portal
  local status=$(echo $response | head -1 | cut -d' ' -f 2)
  ((status == "204"))
}
is_online && echo online || echo offline

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接