답변:
파이프 in의 결과로 x | y
포 그라운드 프로세스 그룹의 일부로 파이프 라인을 포함하도록 서브 쉘이 작성됩니다. 이것은 fork()
무기한으로 서브 쉘을 계속 생성하여 포크 폭탄을 만듭니다.
$ for (( i=0; i<3; i++ )); do
> echo "$BASHPID"
> done
16907
16907
16907
$ for (( i=0; i<3; i++ )); do
> echo "$BASHPID" | cat
> done
17195
17197
17199
그러나 코드가 실행될 때까지는 실제로 포크가 발생하지 않습니다. 이는 코드에서 최종 호출입니다 :
.
포크 폭탄의 작동 방식을 분해하려면 :
:()
-라는 새로운 기능을 정의 :
{ :|: & }
-호출 함수를 백그라운드에서 호출 함수의 다른 인스턴스로 재귀 적으로 파이프하는 함수 정의:
-포크 폭탄 기능을 호출이것은 메모리를 많이 사용하지 않는 경향이 있지만 PID를 빨아 들여 CPU 사이클을 소비합니다.
x | y
, 왜 서브 쉘이 생성된다? 내 이해를 위해 bash가을 볼 때 시스템 호출을 pipe
실행 하여 pipe()
2를 반환합니다 fds
. 이제 command_left가 exec
ed되고 출력이 command_right에 입력으로 공급됩니다. 이제 command_right는 exec
ed입니다. 그렇다면 왜 BASHPID
매번 다른가?
x
그리고 y
당신이 개 별도의 서브 쉘을 가지고 있으므로,이 개 별도의 프로세스에서 실행이 별도의 명령이다. x
쉘과 동일한 프로세스에서 실행되는 경우 x
내장되어 있어야합니다.
코드의 마지막 비트 ;:
는 함수를 실행 중 :(){ ... }
입니다. 여기서 포크가 발생합니다.
세미콜론은 첫 번째 명령을 종료하고 다른 명령을 시작합니다 (예 : 함수 호출) :
. 이 함수의 정의에는 자체 :
호출이 포함되며이 호출의 출력은 백그라운드 버전으로 파이프됩니다 :
. 이것은 프로세스를 무기한으로 진행합니다.
함수 :()
를 호출 할 때마다 C 함수를 호출합니다 fork()
. 결국 이것은 시스템의 모든 프로세스 ID (PID)를 소진합니다.
를 |:&
다른 것으로 바꿔서 무슨 일이 일어나고 있는지 알 수 있습니다.
하나의 터미널 창에서 다음을 수행하십시오.
$ watch "ps -eaf|grep \"[s]leep 61\""
다른 창에서는 약간 수정 된 포크 폭탄 버전을 실행합니다. 이 버전은 스로틀을 시도하여 수행중인 작업을 연구 할 수 있습니다. 우리의 버전은 함수를 호출하기 전에 61 초 동안 대기합니다 :()
.
또한 호출 후 초기 호출도 배경으로합니다. Ctrl+ z를 입력 한 다음을 입력하십시오 bg
.
$ :(){ sleep 61; : | : & };:
# control + z
[1]+ Stopped sleep 61
[2] 5845
$ bg
[1]+ sleep 61 &
이제 jobs
초기 창에서 명령을 실행하면 다음을 볼 수 있습니다.
$ jobs
[1]- Running sleep 61 &
[2]+ Running : | : &
몇 분 후 :
$ jobs
[1]- Done sleep 61
[2]+ Done : | :
한편 우리가 실행중인 다른 창에서 watch
:
Every 2.0s: ps -eaf|grep "[s]leep 61" Sat Aug 31 12:48:14 2013
saml 6112 6108 0 12:47 pts/2 00:00:00 sleep 61
saml 6115 6110 0 12:47 pts/2 00:00:00 sleep 61
saml 6116 6111 0 12:47 pts/2 00:00:00 sleep 61
saml 6117 6109 0 12:47 pts/2 00:00:00 sleep 61
saml 6119 6114 0 12:47 pts/2 00:00:00 sleep 61
saml 6120 6113 0 12:47 pts/2 00:00:00 sleep 61
saml 6122 6118 0 12:47 pts/2 00:00:00 sleep 61
saml 6123 6121 0 12:47 pts/2 00:00:00 sleep 61
그리고이 ps -auxf
프로세스 계층 구조를 보여줍니다 :
$ ps -auxf
saml 6245 0.0 0.0 115184 5316 pts/2 S 12:48 0:00 bash
saml 6247 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
....
....
saml 6250 0.0 0.0 115184 5328 pts/2 S 12:48 0:00 bash
saml 6268 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
saml 6251 0.0 0.0 115184 5320 pts/2 S 12:48 0:00 bash
saml 6272 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
saml 6252 0.0 0.0 115184 5324 pts/2 S 12:48 0:00 bash
saml 6269 0.0 0.0 100988 464 pts/2 S 12:48 0:00 \_ sleep 61
...
...
A killall bash
는 손을 떼기 전에 물건을 멈출 것입니다. 이 방법으로 청소하는 것은 약간 무거운 손 bash
이 될 수 있습니다.
포크 폭탄이 어떤 의사 터미널에서 실행 될지 결정
$ tty
/dev/pts/4
의사 터미널을 죽이십시오
$ pkill -t pts/4
음의 각 호출 bash
하고 sleep
C 함수를 호출입니다 fork()
로부터 bash
명령이 실행 된 곳에서 쉘은.
bash
별도의 터미널에서 실행 중일 수 있습니다. 사용하는 것이 좋습니다 pkill -t pts/2
.