Cố gắng viết một tập lệnh shell tiếp tục kiểm tra máy chủ từ xa, nhưng nó tiếp tục rơi vào câu lệnh khác khi tôi đăng xuất


9

Cố gắng ở đây để viết một kịch bản shell tiếp tục kiểm tra máy chủ của tôi và gửi email cho tôi khi nó bị hỏng.

Vấn đề là khi tôi đăng xuất khỏi kết nối ssh, mặc dù chạy nó &ở cuối lệnh ./stest01.sh &, nó sẽ tự động rơi vào người khác và liên tục gửi thư cho tôi, cho đến khi tôi đăng nhập lại và giết nó.

#!/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
Tôi không phải là một chuyên gia bash, nhưng đại tràng :làm gì? Nó có ý nghĩa với tôi nó là một dấu chấm phẩy ;...
Ned64

3
@ Ned64 Không :có gì. Đây là những gì nó được thiết kế để làm. Ở đây, thay vì đảo ngược bài kiểm tra, họ sử dụng nó để thực hiện lệnh cấm trước đó else.
Kusalananda

@Kusalananda OK, cảm ơn. Nghĩ rằng nó có thể là một lỗi đánh máy có thể giải thích vấn đề.
Ned64

1
Tôi cũng bối rối tại sao người ta lại cố gắng để một kịch bản shell chạy sau khi đăng xuất. Bộ định thời cron hoặc systemd sẽ không phải là lựa chọn tốt hơn cho việc này?
Cliff Armstrong

Câu trả lời:


20

Khi GNU grepcố gắng ghi kết quả của nó, nó sẽ thất bại với trạng thái thoát khác không, bởi vì nó không có nơi nào để ghi đầu ra, vì kết nối SSH đã biến mất.

Điều này có nghĩa là iftuyên bố luôn lấy elsechi nhánh.

Để minh họa điều này (đây không chính xác là những gì xảy ra trong trường hợp của bạn, nhưng nó cho thấy điều gì xảy ra nếu GNU grepkhông thể ghi đầu ra của nó):

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

Ở đây chúng tôi grepcho chuỗi echotạo ra, nhưng chúng tôi đóng cả hai luồng đầu ra grepđể nó không thể ghi ở bất cứ đâu. Như bạn có thể thấy, trạng thái thoát của GNU greplà 2 chứ không phải 0.

Điều này đặc biệt đối với GNU grep, greptrên các hệ thống BSD sẽ không hoạt động giống nhau:

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

Để khắc phục điều này, hãy đảm bảo rằng tập lệnh không tạo đầu ra. Bạn có thể làm điều này với exec >/dev/null 2>&1. Ngoài ra, chúng ta nên sử dụng grepvới -qtùy chọn của nó vì chúng ta hoàn toàn không thích nhìn thấy đầu ra từ nó (điều này thường cũng sẽ tăng tốc grepvì không cần phải phân tích toàn bộ tệp, nhưng trong trường hợp này, nó làm rất ít sự khác biệt về tốc độ vì tập tin quá nhỏ).

Nói ngắn gọn:

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

Bạn cũng có thể sử dụng thử nghiệm pingtrực tiếp, loại bỏ sự cần thiết của một trong các tệp trung gian (và cũng loại bỏ tệp trung gian khác thực sự chỉ chứa một dấu thời gian):

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

Trong cả hai biến thể của tập lệnh ở trên, tôi chọn thoát khỏi vòng lặp khi không đến được máy chủ, chỉ để giảm thiểu số lượng email được gửi. Thay vào đó, bạn có thể thay thế breakbằng ví dụ sleep 10mhoặc một cái gì đó nếu bạn mong muốn máy chủ sẽ xuất hiện trở lại.

Tôi cũng đã điều chỉnh một chút các tùy chọn được sử dụng ping-i 1không có nhiều ý nghĩa với -c 1.

Ngắn hơn (trừ khi bạn muốn nó tiếp tục gửi email khi máy chủ không thể truy cập được):

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

Là một công việc định kỳ chạy mỗi phút (sẽ tiếp tục gửi email mỗi phút nếu máy chủ tiếp tục ngừng hoạt động):

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

Việc sử dụng >&-sẽ đóng fd (như trong, mô tả tệp 1 đã bị đóng), trong khi đóng kết nối SSH sẽ có hiệu ứng khác (một mô tả tệp sẽ vẫn ở xung quanh, nhưng không được kết nối với bất kỳ thứ gì ở phía bên kia.) Tôi nghĩ rằng điểm này vẫn đứng, đó là GNU grep thoát ra khác không nếu nó cố ghi đầu ra và thất bại. Vâng, giải pháp tốt nhất chỉ là kiểm tra trạng thái thoát của ping trực tiếp.
filbranden

4
Có thể an toàn hơn khi chỉ chuyển hướng mọi thứ đến / từ / dev / null cho toàn bộ tập lệnh bằng cách thêm exec </dev/null >/dev/null 2>&1gần đầu. Theo cách đó, nếu eg pingquyết định viết một cái gì đó cho thiết bị lỗi chuẩn thì nó sẽ không gây ra vấn đề gì.
Gordon Davisson

@GordonDavisson Tôi thực sự không thấy lý do gì để kéo stdin từ /dev/nullđây, nhưng tôi đã sắp xếp đầu ra. Cám ơn vì sự gợi ý.
Kusalananda
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.