서브쉘 생성에 대한 Bash 규칙을 오해한 것 같습니다. 나는 대괄호가 항상 자체 프로세스로 실행되는 하위 쉘을 생성한다고 생각했습니다.
그러나 이는 사실이 아닌 것 같습니다. 코드 조각 A(아래)에서 두 번째 sleep
명령은 별도의 셸( pstree
다른 터미널에 의해 결정됨)에서 실행되지 않습니다. 그러나 코드 조각 B에서 두 번째 sleep
명령은하다별도의 쉘에서 실행하십시오. 이 스니펫 간의 유일한 차이점은 두 번째 스니펫에는 대괄호 안에 두 개의 명령이 있다는 것입니다.
서브쉘 생성 규칙을 설명해 줄 수 있는 사람이 있나요?
코드 조각 A:
sleep 5
(
sleep 5
)
코드 조각 B:
sleep 5
(
x=1
sleep 5
)
답변1
괄호는 항상 서브쉘을 시작합니다. 무슨 일이 일어나는지는 bash가 이것이 sleep 5
해당 서브쉘에 의해 실행된 마지막 명령임을 감지하고 exec
대신 호출한다는 것입니다.fork
+exec
. 이 sleep
명령은 동일한 프로세스 내의 하위 쉘을 대체합니다.
즉, 기본 사례는 다음과 같습니다.
( … )
서브셸을 만듭니다. 원래 프로세스는fork
및 를 호출합니다wait
. 하위 프로세스에서 이는 서브쉘입니다.sleep
하위 프로세스의 하위 프로세스가 필요한 외부 명령입니다. 서브쉘 호출fork
및wait
. 하위 하위 프로세스에서:- 하위 하위 프로세스는 외부 명령 → 을 실행합니다
exec
. - 최종 명령이 종료됩니다 →
exit
.
- 하위 하위 프로세스는 외부 명령 → 을 실행합니다
wait
서브셸에서 수행됩니다.
wait
원래 프로세스로 완료되었습니다.
최적화는 다음과 같습니다.
( … )
서브셸을 만듭니다. 원래 프로세스는fork
및 를 호출합니다wait
. 하위 프로세스 내에서는 다음을 호출할 때까지 하위 쉘입니다exec
.sleep
외부 명령이며 프로세스가 수행해야 하는 마지막 작업입니다.- 하위 프로세스는 외부 명령 → 을 실행합니다
exec
. - 최종 명령이 종료됩니다 →
exit
.
wait
원래 프로세스로 완료되었습니다.
호출 후에 다른 것을 추가하는 경우 sleep
이러한 최적화가 발생하지 않도록 서브쉘을 보존해야 합니다.
호출 전에 다른 것을 추가하면 최적화가 이루어질 수 있지만 sleep
(ksh가 이를 수행함) bash는 그렇지 않습니다(이 최적화는 매우 보수적입니다).
답변2
"일반적으로 스크립트의 외부 명령은 하위 프로세스를 분기하는 반면 Bash 내장 기능은 그렇지 않습니다. 따라서 내장 기능은 외부 명령에 해당하는 명령보다 더 빠르게 실행되고 더 적은 시스템 리소스를 사용합니다."
조금 더 아래로:
"괄호 안에 포함된 명령 목록은 하위 쉘로 실행됩니다."
예:
[root@talara test]# echo $BASHPID
10792
[root@talara test]# (echo $BASHPID)
4087
[root@talara test]# (echo $BASHPID)
4088
[root@talara test]# (echo $BASHPID)
4089
OP 코드 사용 예(참을성이 없어서 잠을 더 짧게 자세요):
echo $BASHPID
sleep 2
(
echo $BASHPID
sleep 2
echo $BASHPID
)
산출:
[root@talara test]# bash sub_bash
6606
6608
6608
답변3
@Gilles의 답변에 대한 추가 설명입니다.
Giles가 말했듯이 :The parentheses always start a subshell.
그러나 이러한 하위 쉘에는 중복된 번호가 있을 수 있습니다.
$ (echo "$BASHPID and $$"; sleep 1)
2033 and 31679
$ (echo "$BASHPID and $$"; sleep 1)
2040 and 31679
$ (echo "$BASHPID and $$"; sleep 1)
2047 and 31679
보시다시피 $$는 계속 반복됩니다. 이는 다음과 같은 이유 때문에 예상됩니다(올바른 man bash
행을 찾으려면 이 명령을 실행).
$ LESS=+/'^ *BASHPID' man bash
BASHPID는
현재 bash 프로세스의 프로세스 ID로 확장됩니다. 이는 bash를 다시 초기화할 필요가 없는 하위 쉘과 같은 경우에 따라 $$와 다릅니다.
즉, 쉘이 다시 초기화되지 않으면 $$는 동일합니다.
또는 다음을 사용하세요.
$ LESS=+/'^ *Special Parameters' man bash
특수 매개변수
$는 쉘의 프로세스 ID로 확장됩니다. () 서브쉘에서는 서브쉘이 아닌 현재 쉘의 프로세스 ID로 확장됩니다.
$$
현재 쉘(하위 쉘이 아님)의 ID 입니다 .