Bash에서 외부 명령 실행의 추적 출력을 이해하는 방법은 무엇입니까?

Bash에서 외부 명령 실행의 추적 출력을 이해하는 방법은 무엇입니까?

Ubuntu에서는 datepid 6913을 사용하여 대화형 bash 셸에서 직접 실행합니다.

$ date
Wed Mar  2 23:57:44 EST 2016

그동안 다음 명령을 사용하여 다른 대화형 bash 쉘에서 bash 쉘 6913을 추적하고 있습니다 strace.

    $ sudo strace -f -e trace=process -p 6913
    Process 6913 attached
    clone(Process 9098 attached
    child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,
    child_tidptr=0x7f457c05ca10) = 9098
    [pid  6913] wait4(-1,  <unfinished ...>
    [pid  9098] execve("/bin/date", ["date"], [/* 66 vars */]) = 0
    [pid  9098] arch_prctl(ARCH_SET_FS, 0x7f40d6a4f740) = 0
    [pid  9098] exit_group(0)               = ?
    [pid  9098] +++ exited with 0 +++
    <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED|WCONTINUED, NULL) = 9098
    --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=9098, si_status=0, si_utime=0, si_stime=0} ---
    wait4(-1, 0x7ffea6781518, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)
    clone(Process 9099 attached
    child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 9099
    [pid  9099] clone(Process 9100 attached
    child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 9100
    [pid  9099] wait4(-1,  <unfinished ...>
    [pid  9100] execve("/bin/sed", ["sed", "s:\\([^/]\\)[^/]*/:\\1/:g"], [/* 66 vars */]) = 0
    [pid  9100] arch_prctl(ARCH_SET_FS, 0x7f998bb03840) = 0
    [pid  9100] exit_group(0)               = ?
    [pid  9100] +++ exited with 0 +++
    [pid  9099] <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 9100
    [pid  9099] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=9100, si_status=0, si_utime=0, si_stime=0} ---
    [pid  9099] wait4(-1, 0x7ffea6780c58, WNOHANG, NULL) = -1 ECHILD (No child processes)
    [pid  9099] exit_group(0)               = ?
    [pid  9099] +++ exited with 0 +++
    --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=9099, si_status=0, si_utime=0, si_stime=0} ---
    wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED|WCONTINUED, NULL) = 9099
    wait4(-1, 0x7ffea6780f18, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)

제가 보기에는 출력이 두 부분으로 나누어질 수 있는 것 같습니다.

  1. 먼저 bash 쉘(6913) clone()자체가 하위 프로세스 9098을 생성한 다음 하위 프로세스 9098이 execve() date종료됩니다.

  2. 그 후, bash 쉘(6913) clone()자체는 자식 프로세스(9099)를 생성하고, 그 후 clone()자체적으로 자식 프로세스(9100)를 생성하고, 그 다음 자식 프로세스(9100)를 생성합니다 execve() sed.내 질문두 번째 부분에 관해서 :

    • 마지막 두 개와 clone()마지막 하나는 execve() bash 쉘 6913에서 수신한 SIGCHLD를 처리하는 작업에 속합니까? 이 작업은 무엇을 합니까?

    • 9100을 처리하는 이유는 무엇입니까 execve() sed? 여기서 뭐 하는 거야 sed?

    • 프로세스 9099가 왜 해당 프로세스가 아닌가 execve() sed? 9099가 clone()9100을 만든 다음 9100을 만드는 이유는 무엇입니까 execve() sed? 즉, 하나의 클론 9099 대신 두 개의 연속 클론 9099 및 9100이 필요한 이유는 무엇입니까?


댓글에 답장:

$ echo $PROMPT_COMMAND
pwd2=$(sed "s:\([^/]\)[^/]*/:\1/:g" <<<$PWD)
$ echo $PS1
\u@\h:$pwd2\$

shel 6913 에서 실행한 후 unset PROMPT_COMMAND추적 출력은 다음과 같습니다.

$ sudo strace -f -e trace=process -p 6913
[sudo] password for t: 
Process 6913 attached
clone(Process 12918 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 12918
[pid  6913] wait4(-1,  <unfinished ...>
[pid 12918] execve("/bin/date", ["date"], [/* 66 vars */]) = 0
[pid 12918] arch_prctl(ARCH_SET_FS, 0x7ff00c632740) = 0
[pid 12918] exit_group(0)               = ?
[pid 12918] +++ exited with 0 +++
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED|WCONTINUED, NULL) = 12918
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12918, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, 0x7ffea6781518, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)

이제 위의 처음 두 질문에 답이 있습니다. 세 번째 질문은 아직 잘 모르겠습니다.

답변1

clone(Process 9099 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 9099
[pid  9099] clone(Process 9100 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 9100
[pid  9099] wait4(-1,  <unfinished ...>
[pid  9100] execve("/bin/sed", ["sed", "s:\\([^/]\\)[^/]*/:\\1/:g"], [/* 66 vars */]) = 0

이 두 포크(최신 Linux 시스템에서는 시스템 호출을 사용하여 포크가 수행됨)는 bash가 변수를 clone평가하기 때문입니다 .PROMPT_COMMAND

pwd2=$(sed "s:\([^/]\)[^/]*/:\1/:g" <<<$PWD)

이러한 포크는 이전에 수신된 SIGCHLD 신호와 직접적인 관련이 없습니다.

이것배쉬 매뉴얼설명하다:

Bash는 각 기본 프롬프트를 인쇄하기 전에 PROMPT_COMMAND 변수의 값을 확인합니다. PROMPT_COMMAND가 설정되고 Null이 아닌 값을 갖는 경우 값은 명령줄에 입력된 것처럼 실행됩니다.

내부적으로 bash는 궁극적으로 호출합니다.구문 분석 및 실행내용을 평가합니다 PROMPT_COMMAND. Bash는 수행해야 하는 포크 ​​수를 최소화하려고 노력합니다. 와 같은 간단한 명령문의 경우 pwd2=$PWD분기가 필요하지 않습니다. 더 복잡한 명령문의 경우 하나 이상의 포크를 만들 수 있습니다. 귀하의 경우에는 $( ... )쉘 포크(pid 9099)가 발생하고 대괄호 사이의 명령이 평가됩니다. 내장되지 않은 유틸리티를 호출하면 sed또 다른 포크인 pid 9100이 생성되고 그 뒤에 execve 가 옵니다 /bin/sed.

sed는 여기서 무엇을 하고 있나요?

현재 작업 디렉터리 위의 모든 디렉터리 이름에서 첫 번째 문자를 제외한 모든 문자가 잘리는 것 같습니다.

관련 정보