ฆ่าโปรแกรมหลังจากส่งเอาต์พุตบรรทัดที่กำหนดจากเชลล์สคริปต์


16

พื้นหลัง:

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

ฉันพยายามหาวิธีทดสอบระบบกู้คืน โดยเฉพาะฉันไม่สามารถหาวิธี "หยุด" โปรแกรมในลักษณะที่ควบคุมได้ ฉันกำลังคิดถึงจังหวะเวลาที่คำสั่ง SIGKILL จะทำงานหลังจากเวลาผ่านไประยะหนึ่ง นี่อาจไม่เหมาะเนื่องจากกรณีทดสอบไม่รับประกันว่าจะทำงานด้วยความเร็วเดียวกันทุกครั้ง (ทำงานในสภาพแวดล้อมที่ใช้ร่วมกัน) ดังนั้นการเปรียบเทียบบันทึกกับผลลัพธ์ที่ต้องการอาจเป็นเรื่องยาก

ซอฟต์แวร์นี้พิมพ์บรรทัดสำหรับการวิเคราะห์แต่ละส่วนที่เสร็จสมบูรณ์

คำถาม:

ฉันสงสัยว่ามีวิธีที่ดี / สง่างาม (ในเชลล์สคริปต์) เพื่อจับภาพเอาต์พุตจากโปรแกรมแล้วฆ่าโปรแกรมเมื่อบรรทัด / # บรรทัดที่กำหนดถูกส่งออกโดยโปรแกรมหรือไม่


1
ทำไมคุณต้องหยุดโปรแกรมในเวลาที่กำหนด? เนื่องจากบัฟเฟอร์ออกคุณอาจฆ่าโปรแกรมเป็นเวลานานหลังจากที่มันออกข้อความที่คุณกำลังตรวจสอบ
stardt

@ stardt ฉันต้องการหยุดโปรแกรมในเวลาที่กำหนดเพื่อให้ผลการทดสอบถูกควบคุมและทำซ้ำได้มากขึ้น ฉันได้พบวิธีแก้ไขปัญหานี้แล้ว ฉันจะฆ่าโปรแกรมด้วยตนเองเพียงครั้งเดียวจากนั้นทดสอบเฉพาะรหัสกู้คืน ความพยายามกู้คืนทั้งหมดจะเริ่มจากจุดเดียวกัน ฉันกำลังทดสอบวิธีการที่จะกู้ไม่ว่ามันเกิดปัญหาหลังจาก :) ทั้งหมด
พอล

คำตอบ:


7

สคริปต์ของ wrapper เช่นนี้เป็นแนวทางมาตรฐาน สคริปต์รันโปรแกรมในพื้นหลังแล้ววนซ้ำตรวจสอบล็อกไฟล์ทุกนาทีเพื่อหาสตริง หากพบสตริงโปรแกรมแบ็คกราวน์จะหยุดทำงานและสคริปต์จะหยุดทำงาน

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

15

หากโปรแกรมของคุณจะยุติใน SIGPIPE (ซึ่งเป็นการกระทำเริ่มต้น) มันควรจะเพียงพอที่จะไพพ์เอาต์พุตลงในเครื่องอ่านที่จะออกจากการอ่านบรรทัดนั้น

ดังนั้นมันอาจจะง่ายเหมือน

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

หากคุณต้องการระงับการใช้เอาต์พุตเริ่มต้น

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

ในทำนองเดียวกันหากเราต้องการหยุดหลังจากจำนวนบรรทัดที่หนึ่งสามารถใช้หัวแทน sed เช่น

$ program | head -n$NUMBER_OF_LINES_TO_STOP_AFTER

เวลาที่แน่นอนที่การฆ่าเกิดขึ้นนั้นขึ้นอยู่กับพฤติกรรมการบัฟเฟอร์ของเครื่องเทอร์มินัลตามที่ stardt แนะนำในการแสดงความคิดเห็น


-1 มีข้อบกพร่องร้ายแรงที่นี่ โปรแกรมจะยุติเมื่อ (ถ้า) มันพยายามที่จะเขียนไปยังไปป์ (เสีย) หลังจากsedยุติ OP กล่าวว่า "ซอฟต์แวร์นี้พิมพ์บรรทัดสำหรับการวิเคราะห์แต่ละส่วนที่เสร็จสมบูรณ์" อาจหมายถึงโปรแกรมจะทำส่วนพิเศษให้เสร็จสมบูรณ์หนึ่งส่วน! หลักฐานของแนวคิด: { echo 1; sleep 3; >&2 echo peekaboo; sleep 3; echo 2; } | sed -e '/1/q'. ดูคำตอบนี้ วิธีแก้ไขที่เป็นไปได้: ( program & ) | sed -e '/Suitable text from the line/q'; killall program. ทำให้คำตอบของคุณตระหนักถึงข้อบกพร่องและฉันจะเพิกถอน downvote ของฉัน
Kamil Maciorowski

อืม ... และปัญหาบัฟเฟอร์ทำให้มันไม่น่าเชื่อถือแม้จะมีการปรับปรุงของคุณ (แน่นอนว่ามีผลกระทบต่อการแก้ไขปัญหาทุกอย่างที่ฉันเห็นที่นี่) ฉันชอบที่จะใช้ประโยชน์จากโครงสร้างสัญญาณเมื่อเป็นไปได้ แต่ในบางจุดมันเริ่มสูญเสียความสง่างาม บางทีมันอาจจะดีกว่าที่จะทิ้งเรื่องทั้งหมด
dmckee --- ผู้ดูแลอดีตลูกแมว

7

เป็นทางเลือกแทนคำตอบของ dmckee คำgrepสั่งที่มี-mตัวเลือก (ดูเช่นหน้าคนนี้ ) สามารถใช้คำสั่ง:

compbio | grep -m 1 "Text to match"

เพื่อหยุดเมื่อพบ 1 บรรทัดที่ตรงกับข้อความหรือ

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

เพื่อรอ 10 บรรทัดที่ไม่ตรงกับข้อความที่กำหนด


3

คุณสามารถใช้expect(1)เพื่อดู stdout ของโปรแกรมจากนั้นดำเนินการกระทำที่กำหนดไว้ล่วงหน้าในบางรูปแบบ

#!/usr/bin/env expect

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

หรือซับในสำหรับฝังสคริปต์อื่น:

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

โปรดทราบว่าexpectคำสั่งนั้นไม่ได้มาพร้อมกับระบบปฏิบัติการทุกระบบ คุณอาจต้องติดตั้ง


นี่เป็นทางออกที่ดี ฉันขอแนะนำให้กล่าวถึงset timeout -1การตั้งค่าการหมดเวลาไม่ จำกัด มิฉะนั้นทั้งหมดจะปิดภายใต้การexpectหมดเวลา 10 วินาทีเริ่มต้นของ
pepper_chico

1

คุณสามารถใช้คำสั่ง "while":

คุณต้องไพพ์เอาต์พุตของซอฟต์แวร์ของคุณ (หรือบันทึก) จากนั้นสำหรับแต่ละบรรทัดใหม่ทำการทดสอบตามเงื่อนไขแล้วเรียกใช้ kill -KILL ตัวอย่างเช่น (ฉันทดสอบด้วย / var / log / messages เป็น logfile):

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

หรือด้วยซอฟต์แวร์โดยตรง:

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

คุณต้องเปลี่ยนเส้นทางการบันทึก / ชื่อแอปพลิเคชันใหม่สายที่จะจับคู่และ PID เพื่อฆ่า (คุณสามารถใช้ killall ได้)

ขอให้โชคดีกับซอฟต์แวร์ของคุณ

ฮิวโก้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.