พยายามเขียนเชลล์สคริปที่ทดสอบเซิร์ฟเวอร์จากระยะไกล แต่มันยังคงอยู่ในคำสั่งอื่นเมื่อฉันออกจากระบบ


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 The :ไม่ทำอะไรเลย นี่คือสิ่งที่มันถูกออกแบบมาเพื่อทำ ที่นี่แทน inverting ทดสอบพวกเขาใช้มันจะทำไม่-op elseก่อน
Kusalananda

@ Kusalananda โอเคขอบคุณ คิดว่าอาจเป็นตัวพิมพ์ผิดที่สามารถอธิบายปัญหาได้
Ned64

1
ฉันยังสับสนด้วยว่าทำไมคนเราถึงอยากให้เชลล์สคริปต์ทำงานหลังจากออกจากระบบ ตัวจับเวลา cron หรือ systemd จะไม่เป็นตัวเลือกที่ดีกว่าสำหรับสิ่งนี้หรือไม่
Cliff Armstrong

คำตอบ:


20

เมื่อ GNU grepพยายามเขียนผลลัพธ์มันจะล้มเหลวด้วยสถานะการออกที่ไม่เป็นศูนย์เนื่องจากไม่มีการเขียนผลลัพธ์เนื่องจากการเชื่อมต่อ SSH หายไป

ซึ่งหมายความว่าifคำสั่งนั้นรับelseสาขาเสมอ

เพื่อแสดงนี้ (นี้ไม่ว่าสิ่งที่เกิดขึ้นในกรณีของคุณ แต่มันก็แสดงให้เห็นถึงสิ่งที่เกิดขึ้นถ้า GNU grepไม่สามารถที่จะเขียนออกของมัน):

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

ที่นี่เราgrepใช้สตริงที่echoสร้าง แต่เราปิดสตรีมเอาต์พุตทั้งสองเพื่อgrepให้ไม่สามารถเขียนได้ทุกที่ อย่างที่คุณเห็นสถานะทางออกของ GNU grepคือ 2 มากกว่า 0

นี่คือโดยเฉพาะอย่างยิ่งที่จะ GNU grep, grepบนระบบ BSD จะไม่ทำตัวเหมือนเดิม:

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

เพื่อแก้ไขปัญหานี้ให้แน่ใจว่าสคริปต์ไม่ได้สร้างผลลัพธ์ exec >/dev/null 2>&1คุณสามารถทำเช่นนี้กับ นอกจากนี้เราควรใช้grepกับ-qตัวเลือกเนื่องจากเราไม่สนใจที่จะเห็นผลลัพธ์จากมัน (โดยทั่วไปจะเร่งความเร็วgrepเนื่องจากไม่จำเป็นต้องแยกไฟล์ทั้งหมด แต่ในกรณีนี้มันทำให้น้อยมาก ความแตกต่างของความเร็วเนื่องจากไฟล์มีขนาดเล็กมาก)

ในระยะสั้น:

#!/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โดยตรงลบความจำเป็นสำหรับไฟล์ระดับกลางไฟล์ใดไฟล์หนึ่ง (และกำจัดไฟล์กลางอื่น ๆ ที่เคยมีไฟล์ datestamp อยู่ด้วย):

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

ในฐานะงาน cron รันทุกนาที (จะส่งอีเมลต่อทุกนาทีหากเซิร์ฟเวอร์ยังคงทำงานต่อไป):

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

การใช้>&-จะปิด fd (เช่นเดียวกับ file descriptor 1 ถูกปิด) ในขณะที่การปิดการเชื่อมต่อ SSH จะมีเอฟเฟกต์ที่ต่างออกไป (ไฟล์ descriptor จะยังคงอยู่ แต่ไม่ได้เชื่อมต่อกับสิ่งใดในอีกด้าน) ยังคงยืนอยู่ซึ่ง grep ของ GNU จะออกไม่เป็นศูนย์หากพยายามเขียนเอาต์พุตและล้มเหลว ใช่ทางออกที่ดีที่สุดคือตรวจสอบสถานะทางออกของ ping โดยตรง
filbranden

4
การเปลี่ยนเส้นทางทุกอย่างไปยัง / จาก / dev / null อาจปลอดภัยกว่าสำหรับสคริปต์ทั้งหมดโดยการเพิ่มexec </dev/null >/dev/null 2>&1ใกล้จุดเริ่มต้น ด้วยวิธีนี้ถ้าเช่นpingตัดสินใจที่จะเขียนบางสิ่งไปยัง stderr มันจะไม่ทำให้เกิดปัญหา
Gordon Davisson

@GordonDavisson ฉันไม่เห็นเหตุผลที่จะดึง stdin จาก/dev/nullที่นี่จริงๆแต่ฉันแยกออกผลลัพธ์ ขอบคุณสำหรับคำแนะนำ
Kusalananda
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.