【问题标题】:how to use ping in a script如何在脚本中使用 ping
【发布时间】:2010-12-16 05:18:54
【问题描述】:

我想要一个 bash 脚本:

for c in computers:
do
   ping $c
   if ping is sucessfull:
      ssh $c 'check something'
done

如果我只做ssh 并且计算机没有响应,那么超时将永远存在。所以我正在考虑使用ping 的输出来查看计算机是否还活着。我怎么做?其他想法也会很棒

【问题讨论】:

    标签: bash ssh ping


    【解决方案1】:

    使用ping的返回值:

    for C in computers; do
      ping -q -c 1 $C && ssh $C 'check something'
    done
    

    如果单个 ping (-c 1) 成功,ping 将以值 0 退出。在 ping 超时或无法解析 $C 时,它将以非零值退出。

    【讨论】:

    • 这个答案是错误的,如果你没有为你正在ping的目标IP设置默认路由,你仍然会得到0返回值。
    • @SpaceRocker:非常有趣!我刚刚检查了man ping,我倾向于认为这种行为是ping 中的一个错误,因为在这种情况下我希望返回值为2。 Quote: "如果 ping 根本没有收到任何回复数据包,它将以代码 1 退出。如果同时指定了数据包计数和截止时间,并且在截止时间到达时收到的数据包少于计数,它将也以代码 1 退出。在其他错误时,它以代码 2 退出。否则以代码 0 退出。这使得可以使用退出代码来查看主机是否处于活动状态。" 您对此有何看法这个?
    【解决方案2】:

    ping 命令上使用-w 开关(或-t 在FreeBSD 和OS X 上),然后检查命令的返回值。

    ping -w 1 $c
    RETVAL=$?
    if [ $RETVAL -eq 0 ]; then
        ssh $c 'check something'
    fi
    

    如果您要连接的主机距离较远且延迟较高,您可能需要调整使用-w 传递的参数。

    来自man ping

       -w deadline
              Specify  a  timeout, in seconds, before ping exits regardless of
              how many packets have been sent or received. In this  case  ping
              does  not  stop after count packet are sent, it waits either for
              deadline expire or until count probes are answered or  for  some
              error notification from network.
    

    【讨论】:

      【解决方案3】:

      并非所有网络环境都允许 ping 通过(尽管很多都允许),并且并非所有主机都会响应 ping 请求。我建议不要使用 ping,而是为 ssh 设置连接超时:

      用于计算机中的 c;做 ssh -o ConnectTimeout=2 $c '检查一下' 完毕

      【讨论】:

      • 这是唯一正确的解决方案。当 SSH 连接成功时,ping 失败的原因还有很多。
      【解决方案4】:

      我在 1997 年编写了这样一个脚本,并大量使用了几年:sshall

      它很简单,不是很通用。 另一方面,它支持一些您可能不需要的检查。

      一旦我开始以多种方式使用ssh,我就停止使用或更新此脚本;我现在要么直接编写 shell 循环,要么使用Ansible adhoc commands

      脚本:

      #!/bin/sh
      #
      # $Id: sshall 1259 2017-06-26 16:59:42Z rp $
      
      # sshall: ssh to multiple hosts, *last* arg is command
      # with -i, also accepts input ... I'd rather dup stdin or so, but how?
      
      PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/usr/etc; export PATH
      tmpfile=/tmp/sshall-$$
      
      # error handling
      trap 'rm -f $tmpfile; exit' 1 2 3 4 13 15
      
      #--- cmdline parsing ---#
      #
      
      Puke()
      {
        if [ -n "$*" ]; then echo Fatal error: $* 1>&2; fi
        cat <<ZZ 1>&2
      
      Usage:
        $0 [-v] [-i] [-e] [-b] [-u user] [-H] [-Y] [-P] host1 [host2 [...]] "command"
      
        to issue "ssh host command" for every host
      
        use -i flag to supply input, -e to redirect stderr to stdout,
          -v for progress messages, -b to start in the background,
          -u user to connect as the given user,
          -H to check the hostnames with 'host',
          -Y to check them with 'ypmatch',
          -P to check them with 'ping',
          -o text to pass the given option through to ssh
      
        note: the effect of -i is to call ssh without the -n flag
        take care: -b may fill up your process table if used on many hosts
      
      ZZ
      
        exit 1
      }
      
      input=
      hostlist=
      verbose=
      bg=
      check_w_host=
      check_w_ypmatch=
      check_w_ping=
      user_prefix=
      
      while :
      do
        case "$1" in
          -h|-help|\?*) Puke;;
          -b) bg=1
          if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
          -i) input=1
          if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
          -v) verbose=1
          if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
          -e) errtoout=1
          if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
          -o)
        if [ -n "$o_opt" ]; then Puke "specify only one -o option"; fi
             shift; o_opt="$1"
          if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
          -u) shift; user_prefix="$1@"
          if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
          -H) check_w_host=1
          if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
          -Y) check_w_ypmatch=1
          if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
          -P) check_w_ping=1
          if [ -n "$command" ]; then Puke "options must precede arguments"; fi;;
          -*) Puke "$1 is not a valid option" ;;
          "") break;;
          *) hostlist="$hostlist $command"; command=$1;;
        esac
        shift
      done
      
      if [ -z "$command" ]
      then
        Puke "no command supplied"
      fi
      
      if [ -z "$hostlist" ]
      then
        Puke "no host(s) supplied"
      fi
      
      case "$user_prefix" in
      -*)
        Puke "no -u argument supplied" ;;
      esac
      
      if [ -n "$check_w_host" ]
      then
        for h in $hostlist
        do
          if host 2>&1 >/dev/null
          then
            Puke "host cannot find '$h'"
          fi
        done
      fi
      
      if [ -n "$check_w_ypmatch" ]
      then
        for h in $hostlist
        do
          if ypmatch hosts 2>&1 >/dev/null
          then
            Puke "ypmatch cannot find '$h'"
          fi
        done
      fi
      
      
      #--  OK, start doing useful things ---#
      #
      
      if [ -n "$input" ]
      then
        # read input!
        cat >$tmpfile
        # we can do away with the $tmpfile, with a fork for every host ...
      fi
      
      Ssh()
      {
        case "$errtoout" in
          "") ssh "$@" | sed "s/^/$h: /" ;;
          *)  ssh "$@" 2>&1 | sed "s/^/$h: /" ;;
        esac
      }
      
      Ssh_o()
      {
        case "$o_opt" in
        "") Ssh "$@";;
        *)  Ssh -o "$o_opt" "$@";;
        esac
      }
      
      Ssh_w_tmp()
      {
        if [ -f "$tmpfile" ]
        then
          cat $tmpfile | Ssh_o "$@"
        else
          Ssh_o -n "$@"
        fi
      }
      
      for h in $hostlist
      do
        if [ -z "$check_w_ping" ] || ping $h 2 >/dev/null  # note: "2 >"
        # host is active
        then
          #if [ -z "`finger @$h 2>&1 | grep 'Connection refused$'`" ]
          # host accepts finger - very crude check to see if ssh will work
          # however, finger has been disabled since, where I live
          if true
          then
            if [ -n "$verbose" ]
            then
              echo "executing '$command' on '$h'" 1>&2
            fi
      
            case "$bg" in
            "")
                Ssh_w_tmp $user_prefix$h "$command" ;;
            *)
                Ssh_w_tmp $user_prefix$h "$command" & ;;
              esac
          fi
          fi
      done
      
      rm -f $tmpfile
      

      【讨论】:

        【解决方案5】:

        使用 64 值作为测量工具是不合逻辑的。最好使用接收/丢失数据包的数量。

        这个脚本可以工作:

        RESULT="1"
        PING=$(ping ADDRESS -c 1 | grep -E -o '[0-9]+ received' | cut -f1 -d' ')
        if [ "$RESULT" != "$PING" ]
        then
            DO SOMETHING
        else
            DO SOMETHING
        fi
        

        【讨论】:

          【解决方案6】:

          这是我的技巧:

          #ipaddress shell variable can be provided as an argument to the script.
          while true
          do
             nmap_output=$(nmap -p22 ${ipaddress})
             $(echo ${nmap_output} | grep -q open)
             grep_output=$?
             if [ "$grep_output" == 0 ] ; then
                 #Device is LIVE and has SSH port open for clients to connect
                 break
             else
                 #[01 : bold
                 #31m : red color
                 #0m : undo text formatting
                 echo -en "Device is \e[01;31mdead\e[0m right now .... !\r"
             fi
          done
          #\033[K : clear the text for the new line
          #32 : green color
          echo -e "\033[KDevice is \e[01;32mlive\e[0m !"
          ssh user@${ipaddress}
          

          不仅仅依赖于ping。为什么?
          - 成功的ping 并不能保证您成功访问ssh。您仍然可以将 ping test 添加到此脚本的开头,如果 ping 失败则退出并且不执行上述操作。

          以上bash脚本sn-p,验证您尝试的设备是否 访问会打开 SSH 端口供客户端(您)连接。需要安装nmap 包。

          我不明白您为什么要在该脚本中将ssh 发送到多台计算机。但是,我的适用于 ssh 到一个设备中,并且可以根据您的需要进行修改。

          【讨论】:

            【解决方案7】:

            承认引用 Bash 的原始问题,这里有一个示例供任何希望在 Fish shell 中完成此操作的人使用:

            ping -q -c 1 bogus.local; and echo "pinging the host worked"; or echo "pinging the host didn't work"
            

            【讨论】:

              【解决方案8】:
               while true;
                  do
                      RESULT="1"
                      PING=$(ping 8.8.8.8 -c 1 | grep -E -o '[0-9]+ received' | cut -f1 -d' ')
                      if [ "$RESULT" != "$PING" ]
                      then
                          echo "FAIL"
                          exit 0
                      else
                          echo "connection is okay.." 
                      fi
                  done
              

              【讨论】:

                【解决方案9】:

                在你的 bash 循环中使用它:

                RESULT="64"
                PING=$(ping 127.0.0.1 -c 1 | grep 64 | awk '{print $1}')
                if [ "$RESULT" != "$PING" ]
                then
                   #ping failed
                else
                   #ping successful, do ssh here
                fi
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2013-11-25
                  • 1970-01-01
                  • 2021-10-11
                  • 1970-01-01
                  • 2013-02-03
                  • 1970-01-01
                  • 2022-10-23
                  • 1970-01-01
                  相关资源
                  最近更新 更多