【问题标题】:Wait for Network Interface Before Executing Command执行命令前等待网络接口
【发布时间】:2022-03-18 17:13:25
【问题描述】:

我对如何实现这一点有几个想法。不知道我会如何编写它。

方法一:(可能是更好的选择)

创建一个循环ping服务器直到收到回复然后执行命令 如果在 X 时间内没有收到回复/运行继续脚本。

方法二:

检查网络接口是否有有效的 IP 然后继续脚本

如何在脚本中添加此功能。 awk 或 grep 在这种情况下有用吗?提前感谢您的任何意见。

【问题讨论】:

  • 等待网络接口做什么?
  • 要起床,但不仅仅是起床,哈哈,我需要一个活动连接,我确信我可以连接到互联网。我会让它 ping google 或其他东西进行测试。
  • 也可以。无论接口名称或类型如何,我都可以兼容

标签: bash shell networking


【解决方案1】:

这个命令应该等到它可以联系谷歌或者它已经尝试了 50 次:

for i in {1..50}; do ping -c1 www.google.com &> /dev/null && break; done

for i in {1..50} 循环 50 次或直到执行 breakping -c1 www.google.com向google发送1个ping包,&> /dev/null将所有输出重定向为null,所以没有输出。 && break只有在上一条命令成功完成后才会执行break,所以当ping成功时循环才会结束。

【讨论】:

  • 您能否解释一下脚本的每个部分,这样我就不会在不了解它的工作原理的情况下盲目使用某些东西? ;)
  • 如果在 X 次尝试后无法联系谷歌,我也需要它停止尝试。
  • 连不上google怎么办,试了这么多次还是失败了,我还是想让它继续脚本。在尝试下一部分之前,更重要的是让它有机会建立有效的连接。
  • & > /dev/null 2> /dev/null 部分不是必需的,它只是在运行循环时保持终端输出干净?
  • 可以,不关心终端输出的可以去掉。
【解决方案2】:

我已经在通过 DHCP 配置的板上对此进行了测试。

假设如果特定接口上存在默认网关(在本例中为eth0),那么这是由于板已被 DHCP 分配了 IP(因此默认网关)服务器,这意味着网络已启动并正在运行。

我的问题是,对我来说,只要 LAN/Intranet 中的机器可以访问,即使没有互联网连接(即无法访问 8.8.8.8 或 www.google.com),网络就被认为是启动的.我也不想在 Intranet 中 ping 特定 IP 或域名,因为我不想对子网或哪些设备肯定会启动以及它们的 IP 或域名是什么做出假设。

while ! ip route | grep -oP 'default via .+ dev eth0'; do
  echo "interface not up, will try again in 1 second";
  sleep 1;
done

【讨论】:

    【解决方案3】:

    如何在脚本中添加此功能 -- 杰弗里

    以下是我将如何以模块化方式解决类似情况的一部分...

    await-ipv4-address.sh

    #!/usr/bin/env bash
    
    
    ## Lists IP addresses for given interface name
    ## @returns {number|list}
    ## @param {string} _interface      - Name of interface to monitor for IP address(es)
    ## @param {number} _sleep_intervel - Number of seconds to sleep between checks
    ## @param {number} _loop_limit     - Max number of loops before function returns error code
    ## @author S0AndS0
    ## @copyright AGPL-3.0
    ## @exampe As an array
    ##     _addresses_list=($(await_ipv4_address 'eth0'))
    ##     printf 'Listening address: %s\n' "${_addresses_list[@]}"
    ##     #> Listening address: 192.168.0.2
    ##     #> Listening address: 192.168.0.4
    ## @example As a string
    ##     _addresses_string="$(await_ipv4_address 'eth0' '1' '3')"
    ##     printf 'Listening address(es): %s\n' "${_addresses_string}"
    ##     #> Listening address(es): 192.168.0.2 192.168.0.4
    await_ipv4_address(){
        local _interface="${1:?# Parameter_Error: ${FUNCNAME[0]} not provided an interface}"
        local _sleep_interval="${2:-1}"
        local _loop_limit="${3:-10}"
        if [ "${_sleep_interval}" -lt '0' ] || [ "${_loop_limit}" -le '0' ]; then
            printf 'Parameter_Error: %s requires positive numbers for second and third parameters\n' "${FUNCNAME[0]}" >&2
            return 1
        fi
    
        local _loop_count='0'
        local -a _ipv4_addresses
        while true; do
            for _address in $({ ip addr show ${_interface} | awk '/inet /{print $2}'; } 2>/dev/null); do
                _ipv4_addresses+=("${_address}")
            done
    
            if [ "${#_ipv4_addresses[@]}" -gt '0' ]; then
                printf '%s\n' "${_ipv4_addresses[*]}"
                break
            elif [ "${_loop_count}" -gt "${_loop_limit}" ]; then
                break
            fi
    
            let _loop_count+=1
            sleep "${_sleep_interval}"
        done
    
        [[ "${#_ipv4_addresses[@]}" -gt '0' ]]; return "${?}"
    }
    

    以上来源在 GitHub bash-utilities/await-ipv4-address,查看 ReadMe 文件以获取有关使用 Git 进行更新和错误修复的说明。

    在当前 shell 中获取上述函数...

    source "await-ipv4-address.sh"
    

    ...或在另一个脚本中...

    #!/usr/bin/env bash
    
    
    ## Enable sourcing via absolute path
    __SOURCE__="${BASH_SOURCE[0]}"
    while [[ -h "${__SOURCE__}" ]]; do
        __SOURCE__="$(find "${__SOURCE__}" -type l -ls | sed -n 's@^.* -> \(.*\)@\1@p')"
    done
    __DIR__="$(cd -P "$(dirname "${__SOURCE__}")" && pwd)"
    
    
    source "${__DIR__}/modules/await-ipv4-address/await-ipv4-address.sh"
    
    

    awk 或 grep 在这种情况下有用吗? -- 杰弗里

    两者都可以使用;虽然很像 echoing 我认为 greping 最好在自己的 shell 中完成......我更喜欢 awk 在公共场合,因为有一个整个scripting language 以促进功能蔓延,而printf 因为它不太可能在精简 环境中缺少功能。

    以下是awk 地址的方法,无论 IPv4 还是 IPv6 flavor....

        # ... trimmed for brevity
            for _address in $({ ip addr show ${_interface} | awk '/inet/{print $2}'; } 2>/dev/null); do
                # ... things that get done with an address
            done
    

    ...只是获取更多数据的空间差异。


    无论接口名称或类型如何,我都可以兼容的东西

    三个不同的接口名称示例以及如何覆盖一些默认行为

    1. eth0 上的 IP 等待超过 10 秒
    _ip_addresses_list=($(await_ipv4_address 'eth0'))
    
    1. tun0 上等待超过 30 秒的 IP
    _ip_addresses_list=($(await_ipv4_address 'tun0' '1' '29'))
    
    1. wlan0 上等待一个小步舞曲,同时在两次检查之间休眠 3 秒
    _ip_addresses_list=($(await_ipv4_address 'wlan0' '3' '19'))
    

    注意,如果 await_ipv4_address 获得 board 它将返回非零状态,因此以下...

    _ip_addresses_list=($(await_ipv4_address 'wlan0' '3' '19' || true))
    

    ... 如果您有被此类事情触发的错误陷阱,则可以使用。


    然后对分配的 IP 地址进行处理...

    for _ip_address in "${_ip_addresses_list[@]}"; do
        printf 'IP -> %s\n' "${_ip_address}"
    done
    

    等待网络接口做什么? -- 用户207421

    要起床,但不仅仅是起床,哈哈,我需要一个活动连接,我确信我可以连接到互联网 -- 杰弗里

    只有在通过本地网络交换机/AP 或静态设置分配了 IP 地址的情况下,上述内容不会测试到更大的 Internet 的活动连接;但是,本地 IP 是先决条件...请考虑脚本友好的答案的上述部分,因为它仅旨在很好地执行一件事。

    可靠地检测是否允许连接到万维网的其他部分,请查看digcurl,因为一个成功的ping最喜欢的 DNS意味着允许其他协议。


    您能否解释一下脚本的每个部分,这样我就不会在不了解它的工作原理的情况下盲目使用某些东西? -- 杰弗里

    ...当然...

    await_ipv4_address(){
        local _interface="${1:?# Parameter_Error: ${FUNCNAME[0]} not provided an interface}"
        local _sleep_interval="${2:-1}"
        local _loop_limit="${3:-10}"
        # ...
    }
    
    • local 分配局部范围的变量,help localhelp declare 将显示一些有关更高级用法的有用文档

    • 如果something 未分配,"${something:?Error message}" 将打印Error message

    • "${another_thing:-1}" 将默认为 1 如果 another_thing 未分配分配一个 null

    提示,man --pager='less -p ^"PARAMETERS"' bashSpecial Parameters 部分以及 man --pager='less -p "Parameter Expansion"' bash 部分的结尾可能有助于找到更多可以用变量和东西完成的事情。


        if [ "${_sleep_interval}" -lt '0' ] || [ "${_loop_limit}" -le '0' ]; then
            printf 'Parameter_Error: %s requires positive numbers for second and third parameters\n' "${FUNCNAME[0]}" >&2
            return 1
        fi
    
    • 如果 _sleep_interval_loop_count 由于小于 (-lt) 和小于或等于 (-le) 检查而不是数字,则抛出错误

      李>
    • 如果 if 中的任何一个检查返回 true 则抛出错误,|| 多个检查使得如果左侧返回 false 它会跳到右侧进行检查,而 && 只会在左侧返回时触发 true

    hint man operator 将显示各种运算符的方向性

    • printf 'something\n' >&2something 写入标准错误;应写入所有表现良好的错误,以便生成日志或忽略输出

    • 表现出对可能过度的函数输入的偏执程度


        while true; do
            # ... stuff
        done
    
    • 应谨慎使用,因为如果未正确检查和更新状态,则循环将永远退出。

            for _address in $({ ip addr show ${_interface} | awk '/inet /{print $2}'; } 2>/dev/null); do
                _ipv4_addresses+=("${_address}")
            done
    
    • $({ command | parser; } 2>/dev/null) 技巧是我从这些部分中学到的东西

      • $(something) 在子 shell 中运行 something
      • { one_thing | another_thing; } 是复合命令

      提示,man --pager='less -p "Compound Commands"' bash 应该显示相关文档

      • 2>/dev/null 导致在没有输入返回的地方写入标准错误
    • _preexisting_list+=("element") 通过+=element 附加到_preexisting_list


            if [ "${#_ipv4_addresses[@]}" -gt '0' ]; then
                printf '%s\n' "${_ipv4_addresses[*]}"
                break
            elif [ "${_loop_count}" -gt "${_loop_limit}" ]; then
                break
            fi
    
    • if 部分通过# 符号检查_ipv4_addresses 中的元素数量是否大于0${#_list_name[@]}

    • elif 部分检查函数现在是否应该是 board

    在任何一种情况下,当逻辑被触发时,都会从while 循环中获取break


            let _loop_count+=1
            sleep "${_sleep_interval}"
    
    • let _counter+=1 会将1 添加到_counter 中的任何先前值,并将其分配给_counter

    • sleep 导致循环冷静几秒钟,以便设备可以考虑其他事情


            [[ "${#_ipv4_addresses[@]}" -gt '0' ]]; return "${?}"
    
    • 带有测试括号的 Bash 分号 ([[ is_it_true ]]) 而不是 ||&& 导致 return 返回状态,即如果找到的 IP 地址数量大于 0,则不管测试的真实性如何

    如果有任何疑问,请随时发表评论,以便改进答案。

    【讨论】:

      【解决方案4】:

      您可以执行以下操作

      until ifconfig -l | grep ppp0 >/dev/null 2>&1; do :; done
      

      适用于 MacOS

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多