在 bash 脚本中等待网络

agu*_*cks 10 networking shell-script test

我正在运行一个依赖于网络启动和网络共享安装的脚本。该脚本在登录时运行(启动后自动发生)。问题是在脚本运行时,我通常还没有 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...
Run Code Online (Sandbox Code Playgroud)

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

Gil*_*il' 11

Shell 语法

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

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

while ifconfig | grep "192.168.100." > /dev/null; do …
Run Code Online (Sandbox Code Playgroud)

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

while ! ifconfig | grep -F "192.168.100." > /dev/null; do …
Run Code Online (Sandbox Code Playgroud)

在脚本中,您希望将变量的值与数字进行比较。您使用-gt运算符,它是命令理解的 of条件表达式语法的一部分testtest如果条件表达式为真,则该命令返回 0,如果条件表达式为假,则该命令返回 1。

if test "$x" -gt 200; then
Run Code Online (Sandbox Code Playgroud)

习惯上使用备用名称[test命令。此名称要求命令以参数 结尾]。编写此命令的两种方式完全等效。

if [ "$x" -gt 200 ]; then
Run Code Online (Sandbox Code Playgroud)

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

再次记住,这[是针对条件表达式的,它是带有诸如-n, -gt, ... 之类的运算符的语法,[并不意味着“布尔值”:任何命令都有一个布尔值(退出状态 = 0?)。

检测网络已启动

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

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

如果您需要将这些命令作为登录脚本的一部分运行,请测试您真正需要的资源,而不是是否存在 IP 地址。比如要测试是否/net/somenode/somedir挂载,使用

while ! grep -q /net/somenode/somedir </proc/mounts; do
  sleep 1
done
Run Code Online (Sandbox Code Playgroud)

如果你有新贵或 systemd ......

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