서버를 원격으로 테스트하는 쉘 스크립트를 작성하려고하지만 로그 아웃 할 때 else 문에 계속 빠집니다.


9

내 서버를 계속 테스트하고 다운되면 이메일을 보내주는 쉘 스크립트를 작성하려고합니다.

문제는 ssh 연결에서 로그 아웃 할 때와 &같이 명령이 끝날 때와 함께 실행하더라도 ./stest01.sh &자동으로 다른 것으로 떨어지고 다시 로그인하여 죽일 때까지 중단없이 메일을 계속 보낸다는 것입니다.

#!/bin/bash
while true; do
    date > sdown.txt ;
    cp /dev/null pingop.txt ;
    ping -i 1 -c 1 -W 1 myserver.net > pingop.txt &
    sleep 1 ;
    if
        grep "64 bytes" pingop.txt ;
    then
        :
    else
        mutt -s "Server Down!" myemail@address.com < sdown.txt ;
        sleep 10 ;
    fi
done

1
나는 배쉬 전문가가 아니지만 콜론 :은 무엇을합니까? 그것은 세미콜론이었다 나에게 이해가 될 것입니다 ;...
Ned64

3
@ Ned64 :아무것도하지 않습니다. 이것이 설계된 것입니다. 여기서는 테스트를 뒤집는 대신 테스트를 사용하여 no-op를 수행합니다 else.
Kusalananda

감사합니다. 문제를 설명 할 수있는 오타 일 수도 있다고 생각했습니다.
Ned64

1
또한 로그 아웃 후에 쉘 스크립트를 실행하려고하는 이유가 혼란 스럽습니다. cron 또는 systemd 타이머가 더 나은 선택이 아닌가?
Cliff Armstrong

답변:


20

GNU grep가 결과를 쓰려고하면 SSH 연결이 끊어 졌기 때문에 출력을 쓸 곳이 없기 때문에 0이 아닌 종료 상태로 실패합니다.

이것은 if진술이 항상 else지점을 취하고 있음을 의미합니다 .

이것을 설명하기 위해 (이것은 귀하의 경우에 정확히 일어나지 않지만 GNU grep가 출력을 쓸 수없는 경우 어떻게되는지 보여줍니다 ) :

$ echo 'hello' | grep hello >&- 2>&-
$ echo $?
2

여기서 우리 grepecho생성 하는 문자열 이지만 두 출력 스트림을 모두 닫아서 grep어디에도 쓸 수 없도록합니다. 보다시피 GNU의 종료 상태는 grep0이 아니라 2입니다.

이것은 GNU 특히입니다 grep, grep같은 동작하지 않습니다 BSD 시스템에서 :

$ echo 'hello' | grep hello >&- 2>&-    # using BSD grep here
$ echo $?
0

이를 해결하려면 스크립트가 출력을 생성하지 않는지 확인하십시오. 당신은 이것을 할 수 있습니다 exec >/dev/null 2>&1. 또한 출력을 보는 데 전혀 관심이 없기 때문에 옵션 grep과 함께 사용해야 합니다 (일반적으로 전체 파일을 구문 분석 할 필요가 없으므로 속도가 빨라지 지만이 경우에는 매우 작습니다) 파일이 너무 작아서 속도의 차이).-qgrep

한마디로 :

#!/bin/sh

# redirect all output not redirected elsewhere to /dev/null by default:
exec >/dev/null 2>&1

while true; do
    date >sdown.txt

    ping -c 1 -W 1 myserver.net >pingop.txt

    if ! grep -q "64 bytes" pingop.txt; then
        mutt -s "Server Down!" myemail@address.com <sdown.txt
        break
    fi

    sleep 10
done

ping중간 파일 중 하나가 필요하지 않고 직접 날짜 스탬프가 포함 된 다른 중간 파일을 제거하여 직접 테스트를 사용할 수도 있습니다 .

#!/bin/sh

exec >/dev/null 2>&1

while true; do
    if ! ping -q -c 1 -W 1 myserver.net; then
        date | mutt -s "Server Down!" myemail@address.com
        break
    fi

    sleep 10
done

위 스크립트의 두 가지 변형 모두 호스트에 도달하지 못하면 루프를 종료하고 전송되는 전자 메일 수를 최소화합니다. 서버가 결국 다시 나타날 것으로 예상되는 경우 대신 break예를 들어 sleep 10m또는 다른 것으로 바꿀 수 있습니다.

나는 또한 약간에 사용되는 옵션을 쥐게 한 ping으로 -i 1훨씬 이해가되지 않습니다를 -c 1.

더 짧음 (호스트에 연결할 수 없을 때 이메일을 계속 보내지 않으려는 경우 제외) :

#!/bin/sh

exec >/dev/null 2>&1

while ping -q -c 1 -W 1 myserver.net; do
    sleep 10
done

date | mutt -s "Server Down!" myemail@address.com

1 분마다 실행되는 크론 작업 (서버가 다운 된 경우 1 분마다 이메일을 계속 전송 함) :

* * * * * ping -q -c 1 -W 1 >/dev/null 2>&1 || ( date | mail -s "Server down" myemail@address.com )

를 사용 >&-하면 fd가 닫히고 (파일 설명자 1이 닫힘) SSH 연결을 닫으면 다른 효과가 있습니다 (파일 설명자가 여전히 있지만 다른쪽에는 연결되지 않습니다). 출력을 쓰려고하는데 실패하면 GNU grep이 0이 아닌 상태로 종료됩니다. 가장 좋은 해결책은 핑의 종료 상태를 직접 확인하는 것입니다.
filbranden

4
exec </dev/null >/dev/null 2>&1시작 부분 근처 에 추가하여 전체 스크립트에 대해 모든 것을 / dev / null로 / dev / null로 리디렉션하는 것이 더 안전 할 수 있습니다 . 예를 들어 pingstderr에 무언가를 작성하기로 결정하면 문제가 발생하지 않습니다.
Gordon Davisson

@ GordonDavisson 나는 /dev/null여기서 stdin을 뽑을 이유를 알지 못하지만 출력을 정렬했습니다. 제안 해 주셔서 감사합니다.
Kusalananda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.