ls 명령에서 exec() 후에는 어떻게 됩니까? 상위 프로세스가 콘솔에 출력을 인쇄합니까, 아니면 하위 프로세스에 인쇄합니까?

ls 명령에서 exec() 후에는 어떻게 됩니까? 상위 프로세스가 콘솔에 출력을 인쇄합니까, 아니면 하위 프로세스에 인쇄합니까?

명령 실행에 대한 간단한 질문이 있습니다 ls. 나는 인터넷에서 조사한 내용을 바탕으로 다음 사항을 이해합니다.

  1. 명령을 입력하면 ls쉘이 명령을 해석합니다.

  2. 그런 다음 셸 프로세스는 하위 프로세스를 분기하고 생성하며 상위 프로세스(셸)는 wait()시스템 호출을 실행하여 하위 프로세스가 종료될 때까지 효과적으로 절전 모드로 전환됩니다.

  3. 하위 프로세스는 열려 있는 모든 파일 설명자와 환경을 상속합니다.

  4. 하위 프로세스(셸)는 프로그램의 일부를 실행하여 exec()바이너리 파일이 디스크(파일 시스템)에서 로드 ls되고 ls동일한 프로세스에서 실행되도록 합니다.

  5. ls프로그램 실행이 완료 되면 호출 exit()되며 커널은 하위 프로세스가 종료되었음을 나타내는 신호를 상위 프로세스에 보냅니다.

내 의심은 ls작업이 완료되면 결과를 상위 프로세스로 다시 보내는가, 아니면 출력을 화면에 표시하는가? 출력을 상위 항목으로 다시 보내는 경우 pipe()암시적으로 사용됩니까?

답변1

ls출력해야 할 것을 출력합니다표준 출력. 이를 위해 write다음과 같은 시스템 호출을 호출합니다.

 write(1, "file1  file2...\n", 16)

(또는 유사한 함수를 호출하거나 궁극적으로 시스템 호출을 수행할 가능성이 높습니다 libc)printffwritewrite()

파일 설명자 1(규칙에 따라 stdout)가 이미 열려 있고 무언가를 가리키는 것으로 가정합니다. 실제로 ls파일 설명자 1이 터미널 등을 가리키는지 확인합니다. 터미널을 가리키지 않으면 터미널을 가리킵니다.

 write(1, "file1\nfile2...\n", 15)

즉, 출력이 터미널로 전송되지 않으면 파일에 한 줄에 한 줄씩 씁니다.

당신이 쓸 때 :

 ls file1 file2

ls파일 설명자 1은 쉘의 fd 1과 동일한 자원을 가리킵니다(예를 들어, 에 의해 시작된 대화형 쉘인 경우 xtermxterm에 의해 제어되는 의사 터미널 장치를 가리킵니다). 쉘은 특별한 작업을 수행하지 않고 상속되며 fork해당 O_CLOEXEC플래그는 일반적으로 파일 설명자에 대해 설정되지 않으므로 execve.

당신이 쓰는 경우 :

var=$(ls file1 file2)

쉘은 파이프를 생성하고 하위 프로세스의 fd 1을 파이프의 쓰기 끝에 할당하고 파이프의 다른 쪽 끝을 읽어 변수를 채웁니다 var.

종료 시 마법처럼 수행되는 것이 아니라 프로세스 작업의 일부로 수행됩니다. 이는 셸의 다른 활동과 독립적입니다. 일부 리소스(예: 터미널)에 1개의 연결이 ls있는 또 다른 프로세스 이고 쉘은 실행 중입니다 .fdwaitpid()

그러나 stdout이 터미널이 아닌 경우 출력을 버퍼링하고 충분한 데이터(충분한 킬로바이트)를 축적했거나 출력을 닫거나 종료할 때만 ls호출된다는 것을 알 수 있습니다. write()따라서 종료 시 완료를 찾을 수 있지만 write이러한 I/O 라이브러리가 완료하는 버퍼의 일부로만 가능합니다.flushing

답변2

일반적으로 상위 프로세스는 하위 프로세스가 끝날 때까지 기다립니다.waitpid. 상위 프로세스는 프로세스의 PID를 얻습니다.fork.

이는 자식 프로세스가 어떤 방식으로든 부모 프로세스에 자신이 종료되었거나 발생한 일에 대한 신호를 보내지 않는다는 것을 의미합니다. 이는 하위 프로세스가 아닌 시스템에 의해 수행됩니다.

프로그램의 출력에 대해 이야기하는 경우 상위 프로세스는 fds를 제공하지 않는 한 일반적으로 하위 프로세스의 출력을 수신하지 않습니다. 이는 또한 하위 프로세스가 출력을 인쇄하고아니요부모 프로세스. 상위 프로세스는 프로세스 상태에 대한 정보만 수신합니다. 자세한 내용은 다음을 참조하세요.waitpid매뉴얼 페이지)

답변3

엄밀히 말하자면어느 것도 아니다부모와 자식의 실제 출력은 화면으로 이동하고 대신 운영 체제 커널(특히 tty드라이버)이 출력을 수행합니다. 프로세스는 파일 설명자에만 데이터를 보냅니다.

strace -f /bin/bash "ls;exit"또한 아래와 같이 파일 설명자에 누가 무엇을 쓰고 있는지 명확하게 추측 하지 마십시오 (BASH는 분기하지 않음으로써 "-c ls"를 최적화하는 것 같아서 나중에 ";exit"를 사용했습니다). (bash clone는 no 를 사용합니다 fork):

...
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f9814b5d9d0) = 30029
Process 30029 attached
[pid 30028] rt_sigprocmask(SIG_SETMASK, [],  <unfinished ...>
[pid 30029] rt_sigprocmask(SIG_SETMASK, [],  <unfinished ...>
...
[pid 30028] wait4(-1,  <unfinished ...>
...
[pid 30029] execve("/usr/bin/ls", ["ls"], [/* 72 vars */]) = 0
...
[pid 30029] write(1, "00708022-PTF-26962\nCASE00280714\n"..., 18500708022-PTF-26962) = 185
...
[pid 30029] exit_group(0)               = ?
[pid 30029] +++ exited with 0 +++
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 30029
...

따라서 실제로 PID 30029(하위 프로세스)가 파일 이름을 쓰고 종료된 다음 상위 프로세스가 계속되는 것을 볼 수 있습니다( 이후 wait4).

답변4

성공 하면 exec(3)이를 호출한 프로그램이 더 이상 존재하지 않습니다. 프로그램 에드(program ed)로 대체 되었습니다 exec. 실행하는 새 프로그램은 원래 프로그램, 특히 열려 있는 파일의 환경을 상속합니다.

관련 정보