Kill chương trình sau khi nó xuất ra một dòng nhất định, từ tập lệnh shell


15

Lý lịch:

Tôi đang viết một kịch bản thử nghiệm cho một phần mềm sinh học tính toán. Phần mềm tôi đang kiểm tra có thể mất vài ngày hoặc thậm chí vài tuần để chạy, do đó, phần mềm này có chức năng khôi phục được tích hợp, trong trường hợp xảy ra sự cố hệ thống hoặc mất điện.

Tôi đang cố gắng tìm ra cách kiểm tra hệ thống phục hồi. Cụ thể, tôi không thể tìm ra cách "đánh sập" chương trình một cách có kiểm soát. Tôi đã nghĩ đến việc bằng cách nào đó sắp xếp thời gian một lệnh SIGKILL để chạy sau một khoảng thời gian. Điều này có lẽ không lý tưởng, vì trường hợp thử nghiệm không được đảm bảo chạy cùng tốc độ mỗi lần (nó chạy trong môi trường dùng chung), do đó, việc so sánh các bản ghi với đầu ra mong muốn sẽ khó khăn.

Phần mềm này KHÔNG in một dòng cho mỗi phần phân tích mà nó hoàn thành.

Câu hỏi:

Tôi đã tự hỏi nếu có một cách tốt / thanh lịch (trong một kịch bản shell) để nắm bắt đầu ra từ một chương trình và sau đó giết chương trình khi một dòng / # dòng nhất định được xuất ra bởi chương trình?


1
Tại sao bạn cần dừng chương trình tại một thời điểm cụ thể? Do bộ đệm đầu ra, bạn có thể sẽ giết chương trình một thời gian dài sau khi nó xuất văn bản mà bạn đang kiểm tra.
stardt

@stardt Tôi muốn dừng chương trình tại một thời điểm cụ thể để kết quả kiểm tra được kiểm soát và tái sản xuất nhiều hơn. Tôi đã tìm thấy một cách xung quanh này bây giờ. Tôi sẽ giết chương trình chỉ một lần bằng tay, sau đó chỉ kiểm tra mã khôi phục. Tất cả các nỗ lực phục hồi sẽ bắt đầu từ cùng một điểm. Tôi đang thử nghiệm cách nó phục hồi, chứ không phải là nó bị hỏng như thế nào :)
Paul

Câu trả lời:


7

Một kịch bản bao bọc như thế này là một cách tiếp cận tiêu chuẩn. Kịch bản chạy chương trình trong nền và sau đó lặp lại, kiểm tra tệp nhật ký mỗi phút cho một chuỗi. Nếu chuỗi được tìm thấy thì chương trình nền bị hủy và tập lệnh thoát.

command="prog -foo -whatever"
log="prog.log"
match="this is the what i want to match"

$command > "$log" 2>&1 &
pid=$!

while sleep 60
do
    if fgrep --quiet "$match" "$log"
    then
        kill $pid
        exit 0
    fi
done

14

Nếu chương trình của bạn sẽ chấm dứt trên SIGPIPE (đó là hành động mặc định) thì nó đủ để dẫn đầu ra vào một trình đọc sẽ thoát khi đọc dòng đó.

Vì vậy, nó có thể đơn giản như

$ program | sed -e '/Suitable text from the line/q'

Nếu bạn muốn triệt tiêu đầu ra mặc định, hãy sử dụng

$ program | sed -n -e '/Suitable text from the line/q'

Tương tự như vậy, nếu người ta muốn dừng lại sau một số dòng nhất định, người ta có thể sử dụng đầu thay cho sed, ví dụ:

$ program | head -n$NUMBER_OF_LINES_TO_STOP_AFTER

Thời gian chính xác của ít mà giết xảy ra không phụ thuộc vào hành vi đệm của nhà ga như stardt gợi ý trong các ý kiến.


-1. Có một lỗ hổng nghiêm trọng ở đây. Chương trình sẽ chấm dứt chỉ khi (nếu) nó cố ghi vào ống (bị hỏng) sau khi sedchấm dứt. OP nói "Phần mềm này KHÔNG in một dòng cho mỗi phần phân tích mà nó hoàn thành". Nó có thể có nghĩa là chương trình sẽ hoàn thành một phần thêm! Bằng chứng về khái niệm : { echo 1; sleep 3; >&2 echo peekaboo; sleep 3; echo 2; } | sed -e '/1/q'. Xem câu trả lời này . Cách giải quyết có thể : ( program & ) | sed -e '/Suitable text from the line/q'; killall program. Làm cho câu trả lời của bạn nhận ra lỗ hổng và tôi sẽ thu hồi downvote của tôi.
Kamil Maciorowski

Hmmm ... thực sự. Và vấn đề đệm làm cho nó không đáng tin ngay cả với sự cải thiện của bạn (mặc dù, tất nhiên, điều đó ảnh hưởng đến mọi giải pháp tôi thấy ở đây). Tôi thích sử dụng cơ sở hạ tầng tín hiệu khi có thể, nhưng đến một lúc nào đó, nó bắt đầu mất đi sự thanh lịch. Có lẽ tốt hơn là chỉ để loại bỏ toàn bộ.
dmckee --- ex-moderator mèo con

7

Thay thế cho câu trả lời của dmckee, greplệnh có -mtùy chọn (xem ví dụ: trang man này ) cũng có thể được sử dụng:

compbio | grep -m 1 "Text to match"

dừng lại khi tìm thấy 1 dòng khớp với văn bản hoặc

compbio | grep -v -m 10 "Text to match"

chờ 10 dòng không khớp với văn bản đã cho.


3

Bạn có thể sử dụng expect(1)để xem thiết bị xuất chuẩn của chương trình sau đó thực hiện hành động được xác định trước trên một số mẫu.

#!/usr/bin/env expect

spawn your-program -foo -bar 
expect "I want this text" { close }

Hoặc một lớp lót để nhúng vào tập lệnh khác:

expect -c "spawn your-program -foo -bar; expect \"I want this text\" { close }"

Lưu ý rằng expectlệnh không đi kèm với mọi hệ điều hành theo mặc định. Bạn có thể cần phải cài đặt nó.


Đây là giải pháp tốt đẹp. Tôi khuyên bạn nên đề cập set timeout -1để đặt thời gian chờ không xác định, nếu không tất cả sẽ đóng trong expectthời gian chờ 10 giây mặc định.
pepper_chico

1

Bạn có thể sử dụng câu lệnh "while":

Bạn cần dẫn đầu ra của phần mềm (hoặc nhật ký của phần mềm) và sau đó, với mỗi dòng mới, thực hiện kiểm tra điều kiện, sau đó chạy kill -KILL. Ví dụ: (tôi đã thử nghiệm với / var / log / message dưới dạng logfile):

tail -f /var/log/messages | while read line; do test "$line" = "THE LINE YOU WANT TO MATCH" && kill PIDTOKILL; done

Hoặc với phần mềm trực tiếp:

./biosoftware | while read line; do test "$line" = "THE LINE YOU WANT TO MATCH" && kill PIDTOKILL; done

Bạn cần đặt lại đường dẫn nhật ký / tên ứng dụng, dòng để khớp và PID để hủy (bạn cũng có thể sử dụng killall).

Chúc may mắn với phần mềm của bạn,

Hugo,

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.