
すべての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