서브쉘 프로세스가 없는 서브쉘 예

서브쉘 프로세스가 없는 서브쉘 예

나는 최근에 "서브쉘"이 "서브쉘 프로세스"와 동일하지 않다는 것을 알게 되었습니다(예를 들어 참조)."서브쉘"과 "하위 프로세스"의 정확한 차이점은 무엇입니까?및 POSIX 정의서브쉘그리고하위 프로세스).

이를 확신하기 위해 서브쉘을 생성하지 않고 서브쉘이 생성되었음을 표시(증명)하는 명령을 찾고 있습니다.

현재 내가 시도하는 모든 것은 생성될 때 하위 쉘을 생성하는 것 같습니다.

$ echo $BASHPID; (pwd; cd ..; echo $BASHPID; pwd); pwd      # `( ...)` executed in a subshell
                                                            # and in a child-shell process

$ >&2 ps | ps       # Theoretically executed in two subshells and apparently without child-shells
                    # but I cannot be sure due to the outcome of the next example

$ $ >&2 echo $BASHPID | ps      # `ps` doesn't display a child-shell for the execution of `echo`
953790                          # but `echo $BASHPID` shows a new process that is necessarily
    PID TTY         TIME CMD    # a child-shell since echo is a built-in 
 948538 pts/2   00:00:00 bash
 953791 pts/2   00:00:00 ps

나는 서브쉘이 있다고 해서 반드시 서브쉘이 있다는 것을 의미하지는 않는다는 것을 증명할 방법을 찾고 있습니다.

헤비스트라이크 5.0.17

답변1

Bash 셸에서 하위 셸은 하위 프로세스를 분기하여 구현되므로 하위 프로세스에서 실행되지 않는 하위 셸은 셸에서 표시되지 않습니다.

ksh93은 가능한 경우 하위 쉘 분기를 건너뛰는 내가 아는 유일한 쉘입니다(이 최적화는 여전히 버그가 많으며 AT&T가 이를 작성한 팀을 해체한 후 이를 유지하려고 하는 후속 사람들에 의해 제거 대상으로 고려되었습니다).

예를 들어, 다음과 같은 경우:

 strace ksh93 -c 'pwd; (cd /; umask 0; pwd; exit 2); pwd'

ksh93은 프로세스를 분기하지 않고 대신 다음과 같은 작업을 수행하는 것을 볼 수 있습니다.

openat(AT_FDCWD, ".", O_RDONLY|O_PATH)  = 3
fcntl(3, F_DUPFD, 10)                   = 10
close(3)                                = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
[...]

현재 디렉토리를 fd 10에 저장합니다. 그 다음에:

chdir("/")                              = 0
umask(000)                              = 002

그러면 하위 쉘의 현재 디렉토리와 umask가 변경됩니다. 서브쉘이 종료되면( 시스템 호출이 호출되지 exit 2않음 ):_exit()

fchdir(10)                              = 0
close(10)                               = 0

현재 작업 디렉토리를 복원하려면 다음을 수행하십시오.

umask(002)                              = 000

우마스크를 복원합니다.

일부 셸(예: FreeBSD)은 sh다음과 같은 매우 특정한 상황에서 포크를 건너뛸 수 있습니다.

var=$(printf %04d "$n")

(여기에는 내장된 것이 printf있으며 환경은 변경되지 않았습니다.)

파이프라인에서는 모든 구성 요소가 동시에 실행되어야 하므로 ksh93에서도 별도의 프로세스에서 실행되어야 합니다.

에서는 bash모두 하위 프로세스에서 실행됩니다. AT&T ksh나 zsh 또는 with bash -O lastpipe(비대화형인 경우)에서 가장 오른쪽 프로세스는 그렇지 않습니다(물론 외부 명령(예: )을 실행하려면 하위 프로세스를 포크해야 합니다 ps).

bashbash 인터프리터 파이프라인 구성 요소인 서브셸이 앞에 있는 해당 하위 프로세스에서 직접 실행되기 때문에 ps >&2 | ps추가 프로세스가 표시되지 않습니다 . 예를 들어:(ps)psps

n=0; /bin/true "$((n=1))" | /bin/echo "$((n=2))"; echo "$n"

2bash 와 zsh/ksh93에서 및를 볼 수 있습니다 . 하위 프로세스에서 실행되고 이전에 완료된 서브쉘 프로세스에서 직접 실행됩니다. bash의 (and)와 동일하지만 //에서는 메인 쉘 프로세스에서 완료되고 하위 프로세스는 외부 프로세스를 실행하기 위해 포크만 수행됩니다. 파이프라인의 일부로 실행되지 않을 때와 마찬가지로 유틸리티입니다.022/bin/true/bin/echo/bin/truen=1/bin/echon=2zshkshbash -O lastpipen=2/bin/echo "$((n=2))"

bash( zsh/ 와는 반대로 ksh) 에서는 bash추가 프로세스가 표시 됩니다 (: anything; ps). 최적화는 서브셸에 외부 명령이 하나만 있는 경우에만 수행됩니다. 다음을 exec사용하여 수동으로 최적화 해야 합니다 (: anything; exec ps).

에도 적용됩니다 { ps; } | cat.

답변2

나는 당신이 "서브 쉘"과 "하위 프로세스"(하위 프로세스라고도 함)를 오해하고 있다고 생각하며 bash 매뉴얼 페이지는 혼란을 해결하기 위해 많은 작업을 수행하지 않습니다.

서브쉘은 대략 현재 쉘이 호출될 때 얻는 것입니다 fork(). 포크는 하위 프로세스를 생성하므로 하위 쉘이 생성됩니다.자식 프로세스.

Bash 매뉴얼 페이지에는 bash가 "하위 쉘에서 명령을 실행한다"고 나와 있지만, 여기서 명확하지 않은 점은 외부 프로세스(예: ps)를 실행한 다음 exec()하위 쉘에서 호출되어 실행 중인 bash를 다음의 실행 파일로 대체한다는 것 입니다. 새로운 명령 서브쉘. bash에서 when을 사용하는 경우 와 같은 일부 경우에는 에 ()의해 하위 쉘이 시작 (되고 종료되며 ), 그 사이의 명령은 자체 하위 쉘/하위 프로세스에서 시작될 수 있습니다.

서브쉘이 서브프로세스와 다른 유일한 방법은 서브프로세스가 동일한 실행 파일의 다른 인스턴스일 수도 있고 아닐 수도 있다는 것입니다.

관련 정보