在bash脚本中等待网络


9

我正在运行一个脚本,该脚本依赖于网络正常运行并安装网络共享。该脚本在登录时运行(启动后会自动发生)。问题在于,在脚本运行时,我通常还没有IP地址(DHCP)。目前,我只是将脚本休眠15秒钟,但是我根本不喜欢这种方法,因为我希望能够告诉用户是否有问题。

我的计划是,在没有IP地址的情况下进行循环,然后再继续。至关重要的是,它必须在一段时间后超时。我if [ ifconfig | grep "192.168.100" ];想到的是,但是发生的是grepconsumes ];和不喜欢它。然后bash也变得不高兴,因为它找不到那个];grep吃了。然后,我什至没有执行超时。

有人建议保留一个变量,并在每次迭代中睡一秒钟,然后每次增加该变量。这是我完整的(不起作用的)脚本(我对bash脚本还很陌生):

x=0
while [ ifconfig | grep "192.168.100." > /dev/null ]; do
    echo "no nework"
    if "$x" -gt 200; then
        #Time out here
        exit 1
    x=$((x+1))
    sleep .1
    fi
done

#continue with rest of script...

任何朝着正确方向的指针将不胜感激!


1
如果您的init是systemd,请编写一个等待network-online.target... 的服务文件
jasonwryan 2014年

无需将grep输出重定向到/dev/null。使用-q选项代替。而且我也不认为grep ifconfig是个好主意。为什么不使用它ping呢?
2014年

ping可能会失败,具体取决于所讨论的网络。最好只检查系统的运行配置。
Bratchley 2014年

Answers:


8

Shell语法

您似乎对shell脚本中的条件感到困惑。每个shell命令都有一个退出状态,退出状态是一个介于0到255之间的整数,其中0表示成功,其他任何值表示失败。诸如ifwhile期望布尔操作数的语句检查命令的退出状态,并将0(成功)视为true,将其他任何值(失败)视为false。

例如,grep如果找到模式,则命令返回0,如果未找到模式,则返回1。所以

while ifconfig | grep "192.168.100." > /dev/null; do 

只要192.168.100.在的输出中找到模式,就重复循环ifconfig。请注意,模式会192.168.100.匹配像之类的字符串192x168 1007,因为.在正则表达式中会匹配任何字符;要搜索文字字符串,请将选项传递-Fgrep。要反转条件,请放在!前面。

while ! ifconfig | grep -F "192.168.100." > /dev/null; do 

在脚本的进一步部分,您想要将变量的值与数字进行比较。您使用-gt运算符,该运算符是命令可理解的条件表达式的语法的一部分testtest如果条件表达式为true,则该命令返回0;如果条件表达式为false,则返回1。

if test "$x" -gt 200; then

通常使用[test命令的备用名称。此名称期望命令以参数结尾]。编写此命令的两种方式是完全等效的。

if [ "$x" -gt 200 ]; then

Bash还提供了使用特殊语法编写此命令的第三种方法[[ … ]]。这种特殊的语法比可以支持更多的运算符[,因为它[是受常规解析规则约束的普通命令,而它[[ … ]]是Shell语法的一部分。

同样,请记住,这[是针对条件表达式的,它是使用诸如-n,,-gt…之类的运算符的语法,[并不表示“布尔值”:任何命令都具有布尔值(退出状态= 0?)。

检测网络已启动

您检测网络已启动的方式并不可靠。特别要注意的是,一旦任何网络接口获得指定范围内的IP地址,您的脚本就会被触发。特别是,到那时DNS很可能还没有启动,更不用说安装任何网络共享了。

当有人登录时,您真的需要运行这些命令吗?当网络启动时,使命令自动运行比较容易。具体方法取决于您的发行版以及是否使用NetworkManager。

如果您需要在登录脚本中运行这些命令,请测试您真正需要的资源,而不是IP地址。例如,如果要测试是否/net/somenode/somedir已安装,请使用

while ! grep -q /net/somenode/somedir </proc/mounts; do
  sleep 1
done

如果您有暴发户或系统专家…

那么你可以使用它。例如,使用Upstart,将您的作业标记为start on net-device-up eth0(替换eth0为提供所需网络连接的接口的名称)。使用Systemd,请参见在网络启动后导致脚本执行?


我猜/net/应该是/proc/net
sebix

@sebix不,为什么呢?我不是在谈论Linux的网络配置。我以远程文件系统的挂载点为例,它/net是此类挂载点的常用位置。
吉尔(Gilles)'“ SO-别邪恶”

好的,因此您需要安装的网络驱动器。是否存在更通用的解决方案?
sebix 2015年

@sebix有什么解决方案?需要安装的网络驱动器是目标的一个例子,而不是解决方案的例子。
吉尔斯(Gilles)'所以

1

只需计算输出ip add show例如:

root@xxxxxxlp01 ~ $ ip add sh dev eth3 | grep inet
root@xxxxxxlp01 ~ $ ip add sh dev eth1 | grep inet
root@xxxxxxlp01 ~ $ ip add sh dev eth0 | grep inet
    inet xxx.xxx.64.91/24 brd xxx.xxx.95.255 scope global eth0
    inet6 fe80::224:e8ff:fe78:4dfb/64 scope link
root@xxxxxxlp01 ~ $ ip add sh dev eth0 | grep inet | wc -l
2

然后,您可以根据需要返回的行数进行分支。您可能只是检查它是否为零,如果是,请休眠并重复循环。

未经测试的示例代码:

while [ 1 ]; do

  if [ $(ip add sh dev eth0 | grep inet | wc -l) -ne 0 ]; then
     break
  fi

  sleep 1

done

1

如果至少成功尝试一次,Ping将返回0响应。您可以考虑对要连接的服务器执行ping操作,直到成功为止。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.