모든 bash 전문가에게 전화하여 올바른 방향을 알려주세요. 다음은 1개의 호스트에 필요한 작업만 수행하지만 신뢰할 수 없으며 너무 많은 행을 기록합니다. 더욱 우아하고 실용적으로 만드는 방법은 무엇입니까? 이상적으로는 여러 패킷을 핑하고 변경 사항만 기록할 수 있었으면 좋겠습니다. 또한 여러 호스트에 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
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 명령의 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