Bashスクリプトはホストの変更のみを記録します。

Bashスクリプトはホストの変更のみを記録します。

すべてのbashの専門家に電話して正しい方向を教えてください。以下は、1つのホストに必要な操作だけを実行しますが、信頼できず、行が多すぎます。よりエレガントで実用的にする方法は?理想的には、複数のパケットをpingして変更だけを記録できたらと思います。また、複数のホストでpingを実行します。複数の連続したパケットに対してホストに接続できない場合、または接続できない場合は、1行だけ記録されます。

#!/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

Romeoと同様に、無限ループの代わりに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バージョンを実行している場合)、2つの別々の配列を使用できます。

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

関連情報