중괄호로 배시 서브 쉘 생성


31

따르면 , 중괄호 명령 목록을 배치하는 것은 현재 셀 환경에서 실행되는리스트를 야기한다. 서브 쉘이 작성되지 않습니다 .

ps이것을 실제로 사용 하기 위해 사용

이것은 명령 줄에서 직접 실행되는 프로세스 파이프 라인의 프로세스 계층입니다. 4398은 로그인 쉘의 PID입니다.

sleep 2 | ps -H;
  PID TTY          TIME CMD
   4398 pts/23   00:00:00 bash
   29696 pts/23   00:00:00   sleep
   29697 pts/23   00:00:00   ps

이제 명령 행에서 직접 실행되는 중괄호 사이의 프로세스 파이프 라인에 대한 프로세스 계층 구조를 따릅니다. 4398은 로그인 쉘의 PID입니다. 위의 계층 구조와 비슷하여 모든 것이 현재 쉘 컨텍스트에서 실행된다는 것을 증명합니다 .

{ sleep 2 | ps -H; }
   PID TTY          TIME CMD
    4398 pts/23   00:00:00 bash
    29588 pts/23   00:00:00   sleep
    29589 pts/23   00:00:00   ps

sleep파이프 라인 내부가 중괄호 안에 배치 될 때의 프로세스 계층 구조입니다 (따라서 두 레벨의 중괄호).

{ { sleep 2; } | ps -H; }
  PID TTY          TIME CMD
   4398 pts/23   00:00:00 bash
   29869 pts/23   00:00:00   bash
   29871 pts/23   00:00:00     sleep
   29870 pts/23   00:00:00   ps

설명서에서 중괄호 사이의 명령이 현재 쉘 컨텍스트에서 실행된다고 설명 할 때 세 번째 경우 bash에 실행할 서브 쉘을 작성해야하는 이유는 무엇 sleep입니까?


흥미롭게도, 세 번째 경우에는 내부 그룹이 파이프 라인의 일부이므로 파이프 라인의 일부인 다른 함수 호출과 같이 하위 셸에서 실행되기 때문입니다. 말이 되나요?
Miroslav Koškár

2
나는 단지 "쉘은 반드시해야한다"고 말하지 않을 것입니다 ... 파이프 라인은 쉘 컨텍스트에서 실행 되지 않습니다 . 파이프 라인이 외부 명령으로 만 구성된 경우 하위 프로세스를 작성하면 충분합니다. { sleep 2 | command ps -H; }
Hauke ​​Laging

답변:


26

파이프 라인에서 모든 명령은 서로 다른 프로세스에서 동시에 파이프로 연결된 stdout / stdin과 함께 실행됩니다.

에서

cmd1 | cmd2 | cmd3

세 명령은 모두 다른 프로세스에서 실행되므로 둘 중 적어도 두 개는 하위 프로세스에서 실행되어야합니다. 일부 쉘은 현재 쉘 프로세스에서 빌드 중 하나를 실행하지만 ( read파이프 라인이 스크립트의 마지막 명령 과 같은 경우 또는 파이프 라인이 스크립트의 마지막 명령 인 경우), bash개별 프로세스에서 실행합니다 ( lastpipe최근 bash버전 의 옵션 및 일부 특정 조건 제외) ).

{...}그룹 명령. 해당 그룹이 파이프 라인의 일부인 경우 간단한 명령처럼 별도의 프로세스에서 실행해야합니다.

에서:

{ a; b "$?"; } | c

a; b "$?"별도의 프로세스인지 평가하려면 셸이 필요하므로 하위 셸이 필요합니다. 셸은 b해당 그룹에서 마지막으로 실행되는 명령이므로 포크하지 않아도 최적화 할 수 있습니다. 일부 포탄은 그렇게하지만 분명히하지 않습니다 bash.


" 세 개의 명령은 모두 다른 프로세스에서 실행되므로 둘 중 적어도 두 개는 서브 쉘에서 실행되어야합니다. "이 경우 서브 쉘이 필요한 이유는 무엇입니까? 부모 셸이 트리 프로세스를 생성 할 수 없습니까? 또는 " 서브 쉘에서 실행해야한다 "고 말할 때 쉘이 자체적으로 포크 한 다음 각 cmd1 cmd2 및 cmd3에 대해 exec를 실행합니까? 내가 이것을 실행하면 bash -c "sleep 112345 | cat | cat "하나의 bash 만 생성되고 다른 인터리빙 하위 bash없이 3 개의 하위 항목 만 생성됩니다.
Hakan Baba

" a; b"$? "는 별도의 프로세스이므로 평가할 쉘이 필요합니다. 따라서 서브 쉘이 필요합니다. "추론을 확장 할 수 있습니까? 왜 이해하기 위해 서브 힐이 필요한가요? 그것을 이해하려면 무엇이 필요합니까? 파싱이 필요하다고 가정하지만 다른 것은 무엇입니까? . 부모 셸이 구문 분석 할 수 없습니까 a; b "$?"? 서브 힐에 대한 근본적인 필요성이 있습니까, 아니면 bash에 대한 디자인 결정 / 구현입니까?
Hakan Baba

@HakanBaba, 잠재적 혼란을 피하기 위해 "하위 프로세스"로 변경했습니다.
Stéphane Chazelas

1
@HakanBaba, 파싱은 부모 (코드를 읽는 프로세스, 코드가 전달되지 않은 경우 인터프리터를 실행 한 프로세스 eval)에서 수행되지만 평가 (첫 번째 명령을 실행하고 기다렸다가 두 번째로 실행) stdout이 파이프에 연결된 자식에서 수행됩니다.
Stéphane Chazelas

에서 { sleep 2 | ps -H; }부모 강타보고 sleep 2그 포크 / 간부를 필요로한다. 그러나 { { sleep 2; } | ps -H; }부모 bash에서는 { sleep 2; }다른 말로 bash 코드가 있습니다. 부모는 fork / exec를 처리 할 수 sleep 2있지만 새 bash는 재귀 적으로 발생하여 bash 코드를 처리합니다. 그게 내 이해입니까?
Hakan Baba

19

중괄호를 중첩하면 새 하위 쉘을 호출해야하는 추가 범위의 범위 지정을 작성하는 것으로 나타납니다. ps -H출력 에서 Bash의 두 번째 사본에서이 효과를 볼 수 있습니다 .

첫 번째 수준의 중괄호에 명시된 프로세스 만 원래 Bash 셸 범위 내에서 실행됩니다. 중첩 된 중괄호는 자체 범위가 지정된 Bash 셸에서 실행됩니다.

$ { { { sleep 20; } | sleep 20; } | ps -H; }
  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5012 pts/1    00:00:00   bash
 5014 pts/1    00:00:00     bash
 5016 pts/1    00:00:00       sleep
 5015 pts/1    00:00:00     sleep
 5013 pts/1    00:00:00   ps

복용 | ps -H믹스 밖으로 것은 단지 우리가 중첩 된 중괄호를 볼 수 있습니다, 우리는 실행할 수있는 ps auxf | less다른 쉘에서.

saml     29190  0.0  0.0 117056  3004 pts/1    Ss   13:39   0:00  \_ bash
saml      5191  0.0  0.0 117056  2336 pts/1    S+   14:42   0:00  |   \_ bash
saml      5193  0.0  0.0 107892   512 pts/1    S+   14:42   0:00  |   |   \_ sleep 20
saml      5192  0.0  0.0 107892   508 pts/1    S+   14:42   0:00  |   \_ sleep 20
saml      5068  0.2  0.0 116824  3416 pts/6    Ss   14:42   0:00  \_ bash
saml      5195  0.0  0.0 115020  1272 pts/6    R+   14:42   0:00      \_ ps auxf
saml      5196  0.0  0.0 110244   880 pts/6    S+   14:42   0:00      \_ less

그러나 더 기다립니다!

파이프를 꺼내고이 형식의 명령을 사용하면 실제로 예상되는 것을 볼 수 있습니다.

$ { { { sleep 10; } ; { sleep 10; } ; sleep 10; } } | watch "ps -H"

이제 결과보기 창에서 2 초마다 업데이트가 진행됩니다.

첫 번째는 다음과 같습니다 sleep 10.

  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5676 pts/1    00:00:00   bash
 5678 pts/1    00:00:00     sleep
 5677 pts/1    00:00:00   watch
 5681 pts/1    00:00:00     watch
 5682 pts/1    00:00:00       ps

두 번째는 다음과 같습니다 sleep 10.

  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5676 pts/1    00:00:00   bash
 5691 pts/1    00:00:00     sleep
 5677 pts/1    00:00:00   watch
 5694 pts/1    00:00:00     watch
 5695 pts/1    00:00:00       ps

세 번째는 다음과 같습니다 sleep 10.

  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5676 pts/1    00:00:00   bash
 5704 pts/1    00:00:00     sleep
 5677 pts/1    00:00:00   watch
 5710 pts/1    00:00:00     watch
 5711 pts/1    00:00:00       ps

서로 다른 중첩 레벨의 중괄호에서 호출 되었음에도 불구하고 세 가지 수면은 모두 Bash의 PID 5676 내에 유지됩니다. 따라서 귀하의 문제는 | ps -H.

결론

| ps -H파이프 (예 : 파이프)를 사용 하면 추가 하위 셸이 발생하므로 진행중인 문제를 조사 할 때 해당 방법을 사용하지 마십시오.


따라서 "첫 번째 수준의 중괄호에 지정된 프로세스 만 원래 Bash 셸 범위 내에서 실행됩니다."
xealits

@ xealits-당신이 나에게 묻는 후속 Q입니까?
slm

@ slm 그것은 내가 본 것처럼 대답의 요점을 강조합니다. 중괄호의 첫 번째 레벨에있는 명령은 현재 쉘에서 실행되고 중첩 된 중괄호는 새 쉘을 작성합니다. 괄호는 첫 번째 레벨에서 바로 서브 쉘을 작성하는 데 차이가 있습니다. 내가 틀렸다면 수정하십시오. 그러나 다른 사람들이 지적했듯이 초기 질문에도 파이프 라인이 있습니다. 따라서 별도의 프로세스를 만듭니다. 그리고 중괄호는 별도의 프로세스에 사용될 때 쉘을 만들어야합니다. 아마도 문제의 원인 일 수 있습니다.
xealits

이제 게시물을 다시 읽은 후 내가 틀렸다는 것을 알았습니다. 네스트 문은 파이프 라인의 경우에만 관련이 있습니다. 따라서 중괄호는 별도의 프로세스를 감싸지 않는 한 새로운 쉘을 만들지 않습니다.
xealits

@ xealits-맞습니다.
slm

7

테스트 결과를 게시 할 것인데, bash는 그룹 명령에 대한 하위 쉘을 파이프 라인의 일부 인 경우 에만 호출합니다. 하위 셸에서.

$ { A=1; { A=2; sleep 2; } ; echo $A; }
2

$ { A=1; { A=2; sleep 2; } | sleep 1; echo $A; }
1

내 A도 이것을 보여주고 있습니다.
slm
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.