bash 脚本仅记录主机向上或向下的更改

bash 脚本仅记录主机向上或向下的更改

呼叫所有 bash 专家,请给我一个正确的方向。以下内容仅对 1 台主机执行了我需要的操作,但不可靠,并且记录了太多行。如何让它更优雅、更实用?理想情况下,我希望它能够 ping 多个数据包并仅记录更改。另外,ping 几台主机。当连续多个数据包无法访问/无法访问主机时,仅记录一行。

#!/bin/bash

while [ 1 ]; do
        ping -c 1 -w 2 $1
        if [[ $? == 0 ]]; then
                spd-say "up"
                notify-send "up"
                echo "up $1 $(date +%Y%m%d-%H%M)" >> /tmp/ping.log
        else
                echo "down $1 $(date +%Y%m%d-%H%M)" >> /tmp/ping.log
        fi
        sleep 2m
done;

答案1

像罗密欧一样,我建议使用 cron 而不是无限循环,但为了解决您的日志记录问题,我想出了:

#!/usr/bin/env bash

hosts=("$@")

log=~/tmp/ping.log

[[ ! -f "$log" ]] && touch "$log"

check_log () {
    local h=$1
    local s
    s=$(awk -v h="$h" '$2 == h {print $1}' "$log" | tail -1)
    printf '%s' "$s"
}

for host in "${hosts[@]}"; do
    ping -qc 5 "$host" >/dev/null 2>&1 &
    pids+=([$!]="$host")
done
for pid in "${!pids[@]}"; do
    host=${pids[$pid]}
    s=$(check_log "$host")
    if wait "$pid"; then
        if [[ "$s" == down || -z "$s" ]]; then
            printf '%s\n' "up $host $(date +%Y%m%d-%H%M)" >> "$log"
        fi
    else
        if [[ "$s" == up || -z "$s" ]]; then
            printf '%s\n' "down $host $(date +%Y%m%d-%H%M)" >> "$log"
        fi
    fi
done

check_log函数将在日志文件中搜索给定主机的条目,特别是该主机的最后一个条目以及它是启动还是关闭。

该脚本将循环遍历每个主机,并使用 5 个数据包对它们进行 ping 操作。它将作为后台进程对它们进行 ping 操作,以尝试加快速度。然后它循环遍历后台 ping 命令的 PID 并等待它们完成。如果 ping 成功,它会检查日志以查看该主机的最后一个条目是否失败,如果是,则会记录一条向上该主机的条目,如果不是,则不执行任何操作。如果 ping 命令失败,它将检查日志以查看该主机的最后一个条目是否成功,如果成功,它将记录向下该主机的条目,如果不是,则不执行任何操作。

答案2

我将使用关联数组来保存状态并仅记录状态更改。像这样的东西:

#!/usr/bin/env bash

## This will let us use the host names as keys in the associative array 'status'
declare -A status

while :; do
  for host in "$@"; do
    ## Ping the server and, if the ping is successful, set $isUp to "Up", 
    ## if the ping fails, set $isUp to "Down".
    ping -c 1 -w 2 "$host" &>/dev/null &&
      isUp="Up" || isUp="Down"
    ## If the current value of $isUp isn't the same as what is stored in the
    ## status array for this server, we should report it. 
    if [[ ${status[$host]} != $isUp ]]; then
      spd-say "$host is $isUp"
      notify-send "$host is $isUp"
      printf "%s is %s\n" "$host" "$isUp" >> /tmp/ping.log
      ## save the current status in the array for this server.
      status[$host]=$isUp
    fi
  done
  sleep 2s;
done

然后您可以使用主机名作为参数来运行它:

checkHost.sh hostname1.foo.com hostanme2.bar.com

如果您无法使用关联数组(如果您运行的是旧的 bash 版本),您可以使用两个单独的数组:

hosts=("$@");
while :; do
  for ((i=0;i<${#hosts[@]}; i++)); do
    host=${hosts[i]};
    ping -c 1 -w 2 "$host" &>/dev/null &&
      isUp="Up" || isUp="Down"
    if [[ ${status[i]} != $isUp ]]; then
      spd-say "$host is $isUp"
      notify-send "$host is $isUp"
      printf "%s is %s\n" "$host" "$isUp" >> /tmp/ping.log
      status[i]=$isUp
    fi
  done
  sleep 2s;
done

相关内容