프로세스를 종료 한 후 왜 bash에 '종료 됨'이 표시됩니까?


17

내가 이해하고 싶은 행동은 다음과 같습니다.

$ ps
  PID TTY           TIME CMD
  392 ttys000    0:00.20 -bash
 4268 ttys000    0:00.00 xargs
$ kill 4268
$ ps
  PID TTY           TIME CMD
  392 ttys000    0:00.20 -bash
[1]+  Terminated: 15          xargs
$ ps
  PID TTY           TIME CMD
  392 ttys000    0:00.21 -bash

[1]+ Terminated: 15 xargs프로세스 가 종료 된 후 프로세스를 표시하지 않고 프로세스를 종료 한 후 왜 표시 합니까?

Mac OS X 10.7.5에서 bash를 사용하고 있습니다.

답변:


24

짧은 답변

에서 bash(그리고 dash) 다양한 "작업 상태"메시지는 신호 처리기에서 표시되지만 명시 적으로 검사를 필요로하지 않습니다. 이 확인은 새 프롬프트를 입력하기 전에 만 수행되며 새 명령을 입력하는 동안 사용자를 방해하지 않을 수 있습니다.

kill프로세스가 아직 죽지 않았기 때문에 메시지 가 표시된 후 프롬프트 직전에 메시지 가 표시되지 않습니다. 이것은 kill쉘의 내부 명령 이기 때문에 특히 가능한 조건이므로 실행이 매우 빠르며 포크가 필요하지 않습니다.

killall대신 동일한 실험을 수행하면 일반적으로 즉시 "killed"메시지가 표시됩니다. 시간 / 컨텍스트 스위치 / 외부 명령을 실행하는 데 필요한 모든 작업으로 인해 제어가 셸로 돌아 오기 전에 프로세스가 종료 될 때까지 지연 시간이 길어짐 .

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보다 복잡한 쉘인 예상대로 까다 로웠으며 약간의 gdbfu가 필요했습니다 .

해당 메시지가 생성 될 때의 역 추적은 다음과 같습니다.

(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

죽은 작업 및 공동 확인 전화. 이다 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대해서는 이전 설명이 그대로 유지됩니다 (프로세스는 아직 종료되지 않았습니다).


5

작업 종료 메시지 (명령 행 및 ps출력) 를 피하기 위해 백그라운드로 명령을 구성에 넣을 수 있습니다 sh -c 'cmd &'.

{
ps
echo
pid="$(sh -c 'sleep 60 1>&-  & echo ${!}')"
#pid="$(sh -c 'sleep 60 1>/dev/null  & echo ${!}')"
#pid="$(sh -c 'sleep 60 & echo ${!}' | head -1)"
ps
kill $pid
echo
ps
}

그건 그렇고, bash쉘 옵션을 사용 set -b하거나 set -o notify각각 을 사용하여 즉시 작업 종료 알림을받을 수 있습니다 .

이 경우 " 신호를 bash수신 SIGCHLD하고 신호 처리기 bash가 현재 포 그라운드 프로세스가 완료되기를 기다리는 중이라도"알림 메시지를 즉시 표시합니다 "(아래 참조 참조).

사이에 세 번째 작업 제어 알림 set +b모드 (기본 모드)와 set -b(현재 명령 행에 이미 입력 한 내용을 손상시키지 않고 즉시 작업 종료 알림을 받도록 ctrl-x ctrl-v) bashSimon Tatham 의 패치가 필요합니다. 패치 자체 및 추가 정보 는 bash (1)의 합리적인 비동기 작업 알림을 참조하십시오 .

그래서 단지의 반복하자 Matteo ItaliagdbA에 대한 -fu bash즉시 작업 종료 통지하도록 설정되어있는 쉘을 set -b.

# 2 Terminal.app windows

# terminal window 1
# start Bash compiled with -g flag
~/Downloads/bash-4.2/bash -il
set -bm
echo $$ > bash.pid

# terminal window 2
gdb -n -q
(gdb) set print pretty on
(gdb) set history save on
(gdb) set history filename ~/.gdb_history
(gdb) set step-mode off
(gdb) set verbose on
(gdb) set height 0
(gdb) set width 0
(gdb) set pagination off
(gdb) set follow-fork-mode child
(gdb) thread apply all bt full
(gdb) shell cat bash.pid
(gdb) attach <bash.pid>
(gdb) break pretty_print_job

# terminal window 1
# cut & paste
# (input will be invisible on the command line)
sleep 600 &   

# terminal window 2
(gdb) continue
(gdb) ctrl-c

# terminal window 1
# cut & paste
kill $!

# terminal window 2
(gdb) continue
(gdb) bt

Reading in symbols for input.c...done.
Reading in symbols for readline.c...done.
Reading in symbols for y.tab.c...done.
Reading in symbols for eval.c...done.
Reading in symbols for shell.c...done.
#0  pretty_print_job (job_index=0, format=0, stream=0x7fff70bb9250) at jobs.c:1630
#1  0x0000000100032ae3 in notify_of_job_status () at jobs.c:3561
#2  0x0000000100031e21 in waitchld (wpid=-1, block=0) at jobs.c:3202
#3  0x0000000100031a1a in sigchld_handler (sig=20) at jobs.c:3049
#4  <signal handler called>
#5  0x00007fff85a9f464 in read ()
#6  0x00000001000b39a9 in rl_getc (stream=0x7fff70bb9120) at input.c:471
#7  0x00000001000b3940 in rl_read_key () at input.c:448
#8  0x0000000100097c88 in readline_internal_char () at readline.c:517
#9  0x0000000100097dba in readline_internal_charloop () at readline.c:579
#10 0x0000000100097de6 in readline_internal () at readline.c:593
#11 0x0000000100097842 in readline (prompt=0x100205f80 "noname:~ <yourname>$ ") at readline.c:342
#12 0x0000000100007ab7 in yy_readline_get () at parse.y:1443
#13 0x0000000100007bbe in yy_readline_get () at parse.y:1474
#14 0x00000001000079d1 in yy_getc () at parse.y:1376
#15 0x000000010000888d in shell_getc (remove_quoted_newline=1) at parse.y:2231
#16 0x0000000100009a22 in read_token (command=0) at parse.y:2908
#17 0x00000001000090c1 in yylex () at parse.y:2517
#18 0x000000010000466a in yyparse () at y.tab.c:2014
#19 0x00000001000042fb in parse_command () at eval.c:228
#20 0x00000001000043ef in read_command () at eval.c:272
#21 0x0000000100004088 in reader_loop () at eval.c:137
#22 0x0000000100001e4d in main (argc=2, argv=0x7fff5fbff528, env=0x7fff5fbff540) at shell.c:749

(gdb) detach
(gdb) quit

멋있는! 그러나 다른 방법이있을 수 있다고 생각하십니까? : 나는 이것을 시도하고있다 pid="$(sh -c 'cat "$fileName" |less & echo ${!}')"미만 표시 실 거예요
물병 전원을
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.