Câu trả lời ngắn
Trong bash
(và dash
) các thông báo "trạng thái công việc" khác nhau không được hiển thị từ các trình xử lý tín hiệu, nhưng yêu cầu kiểm tra rõ ràng. Kiểm tra này chỉ được thực hiện trước khi một lời nhắc mới được cung cấp, có thể không làm phiền người dùng trong khi anh ta / cô ta đang gõ một lệnh mới.
Thông báo không được hiển thị ngay trước lời nhắc sau khi kill
hiển thị có thể do quá trình chưa chết - đây là điều kiện đặc biệt có thể xảy ra do kill
là một lệnh nội bộ của shell, vì vậy nó rất nhanh để thực thi và không cần phải giả mạo.
killall
Thay vào đó, thực hiện cùng một thử nghiệm với , thường mang lại thông báo "bị giết" ngay lập tức, ký hiệu rằng công tắc thời gian / bối cảnh / bất cứ điều gì cần thiết để thực hiện lệnh bên ngoài gây ra độ trễ đủ lâu để quá trình bị hủy trước khi điều khiển quay trở lại trình bao .
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
$
Câu trả lời dài
dash
Trước hết, tôi đã xem xét các dash
nguồn, vì dash
thể hiện hành vi tương tự và mã chắc chắn đơn giản hơn bash
.
Như đã nói ở trên, điểm có vẻ là các thông báo trạng thái công việc không được phát ra từ bộ xử lý tín hiệu (có thể làm gián đoạn luồng điều khiển vỏ "bình thường"), nhưng chúng là hậu quả của việc kiểm tra rõ ràng (một showjobs(out2, SHOW_CHANGED)
cuộc gọi trong dash
) được thực hiện chỉ trước khi yêu cầu đầu vào mới từ người dùng, trong vòng REPL.
Do đó, nếu shell bị chặn chờ người dùng nhập vào thì không có thông báo nào được phát ra.
Bây giờ, tại sao kiểm tra không được thực hiện ngay sau khi kill cho thấy quá trình thực sự bị chấm dứt? Như đã giải thích ở trên, có lẽ vì nó quá nhanh. kill
là một lệnh nội bộ của shell, vì vậy nó rất nhanh để thực thi và không cần phải sử dụng, do đó, ngay sau khi kill
kiểm tra được thực hiện, quy trình vẫn còn sống (hoặc, ít nhất, vẫn đang bị giết).
bash
Như mong đợi, bash
là một lớp vỏ phức tạp hơn nhiều, khó hơn và cần một số gdb
-fu.
Backtrace cho khi thông điệp đó được phát ra là một cái gì đó như
(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
Cuộc gọi kiểm tra các công việc đã chết & co. là notify_of_job_status
(nó ít nhiều tương đương với showjobs(..., SHOW_CHANGED)
in dash
); # 0- # 1 liên quan đến hoạt động bên trong của nó; 6-8 là mã trình phân tích cú pháp do yacc tạo; 10-12 là vòng lặp REPL.
Địa điểm thú vị ở đây là # 4, tức là từ nơi notify_and_cleanup
cuộc gọi đến. Dường như bash
, không giống như dash
, có thể kiểm tra các công việc bị chấm dứt ở mỗi ký tự được đọc từ dòng lệnh, nhưng đây là những gì tôi tìm thấy:
/* 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 */
}
Vì vậy, trong chế độ tương tác, cố tình trì hoãn kiểm tra cho đến khi được cung cấp lời nhắc mới, có thể không làm phiền người dùng nhập lệnh. Về lý do tại sao kiểm tra không phát hiện ra quy trình chết khi hiển thị lời nhắc mới ngay sau đó kill
, phần giải thích trước đó được giữ lại (quy trình chưa chết).
pid="$(sh -c 'cat "$fileName" |less & echo ${!}')"
nhưng sẽ không xuất hiện