Kurze Antwort
In bash
(und dash
) werden die verschiedenen "Auftragsstatus" -Nachrichten nicht von Signalhandlern angezeigt, sondern erfordern eine explizite Prüfung. Diese Überprüfung wird nur durchgeführt, bevor eine neue Eingabeaufforderung bereitgestellt wird, um den Benutzer wahrscheinlich nicht zu stören, während er einen neuen Befehl eingibt.
Die Meldung wird nicht direkt vor der Eingabeaufforderung kill
angezeigt, nachdem das angezeigt wird, wahrscheinlich, weil der Prozess noch nicht beendet ist. Dies ist eine besonders wahrscheinliche Bedingung, da kill
es sich um einen internen Befehl der Shell handelt. Daher ist die Ausführung sehr schnell und erfordert kein Verzweigen.
Wenn Sie dasselbe Experiment mit killall
ausführen, wird in der Regel sofort die Meldung "kill" ausgegeben. Dies bedeutet , dass die zum Ausführen eines externen Befehls erforderlichen Zeit- / Kontextwechsel / Ereignisse eine Verzögerung verursachen, die lang genug ist, damit der Prozess abgebrochen werden kann, bevor das Steuerelement zur Shell zurückkehrt .
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
$
Lange Antwort
dash
Zunächst habe ich mir die dash
Quellen angeschaut, da sie dash
das gleiche Verhalten aufweisen und der Code sicherlich einfacher ist als bash
.
Wie oben erwähnt, scheint der Punkt zu sein, dass Jobstatusnachrichten nicht von einem Signalhandler ausgegeben werden (was den "normalen" Shell-Steuerungsfluss unterbrechen kann), sondern die Folge einer expliziten Überprüfung (eines showjobs(out2, SHOW_CHANGED)
Aufrufs dash
) sind, die durchgeführt wird Nur vor dem Anfordern neuer Eingaben vom Benutzer in der REPL-Schleife.
Wenn also die Shell blockiert ist und auf Benutzereingaben wartet, wird keine solche Nachricht ausgegeben.
Warum zeigt die Prüfung, die unmittelbar nach dem Kill durchgeführt wurde, nicht, dass der Prozess tatsächlich beendet wurde? Wie oben erklärt, wahrscheinlich, weil es zu schnell ist. kill
ist ein interner Befehl der Shell, daher ist die Ausführung sehr schnell und es ist kein Verzweigen erforderlich. Wenn kill
der Prozess unmittelbar nach der Überprüfung noch aktiv ist (oder zumindest noch beendet wird), wird er dennoch ausgeführt.
bash
Wie erwartet bash
war es schwieriger und erforderte etwas gdb
-fu , eine viel komplexere Shell zu sein .
Die Rückverfolgung, wann diese Nachricht ausgegeben wird, ist ungefähr so
(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
Der Anruf, der nach toten Jobs & Co sucht. ist notify_of_job_status
(es ist mehr oder weniger das Äquivalent von showjobs(..., SHOW_CHANGED)
in dash
); # 0- # 1 hängen mit seiner inneren Arbeit zusammen; 6-8 ist der von yacc generierte Parser-Code. 10-12 ist die REPL-Schleife.
Der interessante Ort ist hier # 4, dh von wo der notify_and_cleanup
Anruf kommt. Es sieht so aus bash
, als ob im Gegensatz dash
zu jedem Zeichen, das von der Kommandozeile gelesen wird, nach beendeten Jobs gesucht werden muss, aber hier ist, was ich gefunden habe:
/* 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 */
}
Im interaktiven Modus ist es daher beabsichtigt , die Prüfung zu verzögern, bis eine neue Eingabeaufforderung angezeigt wird, um den Benutzer bei der Eingabe von Befehlen wahrscheinlich nicht zu stören. Was den Grund angeht, warum die Prüfung den toten Prozess nicht erkennt, wenn die neue Eingabeaufforderung unmittelbar nach dem angezeigt wird kill
, gilt die vorherige Erklärung (der Prozess ist noch nicht tot).
pid="$(sh -c 'cat "$fileName" |less & echo ${!}')"
aber weniger wird nicht auftauchen