คำตอบสั้น ๆ
ในbash
(และdash
) ข้อความ "สถานะงาน" ต่าง ๆ จะไม่แสดงจากตัวจัดการสัญญาณ แต่ต้องมีการตรวจสอบอย่างชัดเจน การตรวจสอบนี้จะดำเนินการก่อนที่จะได้รับพรอมต์ใหม่อาจไม่รบกวนผู้ใช้ในขณะที่เขา / เธอกำลังพิมพ์คำสั่งใหม่
ข้อความไม่ปรากฏขึ้นก่อนที่พรอมต์kill
จะปรากฏขึ้นเนื่องจากกระบวนการยังไม่ตาย - นี่เป็นเงื่อนไขที่เป็นไปได้โดยเฉพาะเนื่องจากkill
เป็นคำสั่งภายในของเชลล์ดังนั้นจึงรวดเร็วในการดำเนินการและไม่ต้องการการฟอร์ก
ทำการทดลองแบบเดียวกันโดยkillall
ปกติจะให้ข้อความ "ถูกฆ่า" ทันทีลงชื่อว่าเวลา / บริบทสวิตช์ / สิ่งที่จำเป็นในการดำเนินการคำสั่งภายนอกทำให้เกิดความล่าช้านานพอที่กระบวนการจะถูกฆ่าก่อนที่การควบคุมจะกลับสู่เชลล์ .
matteo@teokubuntu:~$ dash
$ sleep 60 &
$ ps
PID TTY TIME CMD
4540 pts/3 00:00:00 bash
4811 pts/3 00:00:00 sh
4812 pts/3 00:00:00 sleep
4813 pts/3 00:00:00 ps
$ kill -9 4812
$
[1] + Killed sleep 60
$ sleep 60 &
$ killall sleep
[1] + Terminated sleep 60
$
คำตอบที่ยาว
dash
ก่อนอื่นฉันได้ดูที่dash
แหล่งข้อมูลเนื่องจากการdash
แสดงพฤติกรรมเดียวกันและรหัสนั้นง่ายกว่าbash
แน่นอน
ดังที่กล่าวไว้ข้างต้นจุดดูเหมือนว่าข้อความสถานะงานจะไม่ถูกปล่อยออกมาจากตัวจัดการสัญญาณ (ซึ่งสามารถขัดจังหวะการควบคุมการไหลของเชลล์ "ปกติ") แต่พวกเขาเป็นผลมาจากการตรวจสอบอย่างชัดเจน (การshowjobs(out2, SHOW_CHANGED)
โทรเข้าdash
) ที่ดำเนินการ เฉพาะก่อนที่จะขออินพุตใหม่จากผู้ใช้ในลูป REPL
ดังนั้นหากเชลล์ถูกบล็อกรอการป้อนข้อมูลของผู้ใช้ไม่มีข้อความดังกล่าวถูกปล่อยออกมา
ตอนนี้เหตุใดการตรวจสอบจึงไม่ดำเนินการหลังจากการฆ่าแสดงว่ากระบวนการนั้นสิ้นสุดจริง ตามที่อธิบายไว้ข้างต้นอาจเป็นเพราะมันเร็วเกินไป kill
เป็นคำสั่งภายในของเชลล์ดังนั้นจึงรวดเร็วในการดำเนินการและไม่ต้องการฟอร์กดังนั้นเมื่อทันทีหลังจากkill
การตรวจสอบถูกดำเนินการกระบวนการยังมีชีวิตอยู่ (หรืออย่างน้อยก็ยังคงถูกฆ่า)
bash
อย่างที่คาดไว้bash
การเป็นเปลือกที่ซับซ้อนมากขึ้นนั้นยากกว่าและจำเป็นต้องมีgdb
-fu
backtrace สำหรับเมื่อข้อความถูกปล่อยออกมาเป็นสิ่งที่ต้องการ
(gdb) bt
#0 pretty_print_job (job_index=job_index@entry=0, format=format@entry=0, stream=0x7ffff7bd01a0 <_IO_2_1_stderr_>) at jobs.c:1630
#1 0x000000000044030a in notify_of_job_status () at jobs.c:3561
#2 notify_of_job_status () at jobs.c:3461
#3 0x0000000000441e97 in notify_and_cleanup () at jobs.c:2664
#4 0x00000000004205e1 in shell_getc (remove_quoted_newline=1) at /Users/chet/src/bash/src/parse.y:2213
#5 shell_getc (remove_quoted_newline=1) at /Users/chet/src/bash/src/parse.y:2159
#6 0x0000000000423316 in read_token (command=<optimized out>) at /Users/chet/src/bash/src/parse.y:2908
#7 read_token (command=0) at /Users/chet/src/bash/src/parse.y:2859
#8 0x00000000004268e4 in yylex () at /Users/chet/src/bash/src/parse.y:2517
#9 yyparse () at y.tab.c:2014
#10 0x000000000041df6a in parse_command () at eval.c:228
#11 0x000000000041e036 in read_command () at eval.c:272
#12 0x000000000041e27f in reader_loop () at eval.c:137
#13 0x000000000041c6fd in main (argc=1, argv=0x7fffffffdf48, env=0x7fffffffdf58) at shell.c:749
การโทรที่ตรวจสอบหางานที่ตายแล้ว & co. คือnotify_of_job_status
(มันมากหรือน้อยเทียบเท่าshowjobs(..., SHOW_CHANGED)
ในdash
); # 0- # 1 เกี่ยวข้องกับการทำงานภายใน 6-8 เป็นรหัสแยกวิเคราะห์ yacc ที่สร้างขึ้น; 10-12 คือวงวน REPL
สถานที่ที่น่าสนใจที่นี่คือ # 4 นั่นคือจากที่notify_and_cleanup
โทรมา ดูเหมือนว่าbash
ไม่เหมือนdash
กันอาจตรวจสอบงานที่ยกเลิกที่ตัวละครแต่ละตัวอ่านจากบรรทัดคำสั่ง แต่นี่คือสิ่งที่ฉันพบ:
/* If the shell is interatctive, but not currently printing a prompt
(interactive_shell && interactive == 0), we don't want to print
notifies or cleanup the jobs -- we want to defer it until we do
print the next prompt. */
if (interactive_shell == 0 || SHOULD_PROMPT())
{
#if defined (JOB_CONTROL)
/* This can cause a problem when reading a command as the result
of a trap, when the trap is called from flush_child. This call
had better not cause jobs to disappear from the job table in
that case, or we will have big trouble. */
notify_and_cleanup ();
#else /* !JOB_CONTROL */
cleanup_dead_jobs ();
#endif /* !JOB_CONTROL */
}
ดังนั้นในโหมดอินเทอร์แอคทีฟมันตั้งใจที่จะชะลอการตรวจสอบจนกว่าจะมีพรอมต์ใหม่ให้ซึ่งอาจจะไม่รบกวนผู้ใช้ที่ป้อนคำสั่ง สำหรับสาเหตุที่การตรวจสอบไม่พบกระบวนการที่ตายแล้วเมื่อแสดงพรอมต์ใหม่ทันทีหลังจากkill
คำอธิบายก่อนหน้าถือ (กระบวนการยังไม่ตาย)
pid="$(sh -c 'cat "$fileName" |less & echo ${!}')"
แต่จะไม่ปรากฏขึ้นอีกเลย