파이프가 스크립트의 하위 쉘로 흘러 들어가는 것을 방지하는 방법

파이프가 스크립트의 하위 쉘로 흘러 들어가는 것을 방지하는 방법

저는 PHP 스크립트에 파이프를 연결하고 있습니다(아래의 인위적인 예 참조). 불행히도 파이프는 스크립트의 쉘 명령으로 실수로 흘러 들어가므로 nano는 STDIN을 차단하기 때문에 실행할 수 없습니다.

나는 쉘 명령이 메인 스크립트에 파이프된 STDIN과 완전히 독립적으로 실행되기를 원합니다. 따라서 PHP 스크립트는 서브쉘에 도달하지 않도록 어떤 방식으로든 STDIN을 "먹어야" 합니다. 어떻게 해결할 수 있나요?

둘 다 동일한 결과를 제공한다는 exec()점에 유의하십시오 .system()passthru()

$ echo -e "World\nEverybody" | php script.php
Hello World
Received SIGHUP or SIGTERM
Hello Everybody
Received SIGHUP or SIGTERM

script.php:

<?php

foreach(file("php://stdin") as $name) {
  echo "Hello $name";
  passthru("nano");
}

?>

환경:

  • PHP 7.1.14/PHP 5.6.30
  • GNU 배쉬, 버전 3.2.57

답변1

예, 다음을 수행하면 프로세스는 상위 파일 설명자를 상속받습니다.

존재하다

php -r 'passthru("nano");'

php쉘의 stdin(또는 대화형 쉘의 프롬프트에서 호출된 경우 tty 장치)은 상속되고 또한 상속됩니다(그리고 stdout은 nano출력을 검색하고 전달하는 데 사용되는 파이프이므로 모든 편집자가 그렇지는 않은 것 같습니다) 그렇게 하면 여기에서 사용할 수 있습니다.)phpnanonanosystem()

존재하다:

something | php -r 'passthru("nano");'

이제 phpstdin을 사용하여 파이프를 호출하고 있으며 something반대쪽 끝에는 stdout이 있습니다. 그리고 nano그것을 상속받을 것입니다.

phpstdin을 파이프로 만들고 nanostdin이 쉘의 stdin이 무엇이든 간에 , 어떻게든 해당 리소스를 파이프에 전달하여 php만들어야 합니다 (또는 php실행 중인 쉘 passthru의 표준 입력이 되도록 해야 합니다 ) nano. 예를 들어 다음과 같이 할 수 있습니다.

{ something 3<&- | php -r 'passthru("nano <&3 3<&-");'; } 3<&0

{...;}fd 0(stdin)의 리소스를 명령 그룹의 fd 3에서도 사용할 수 있도록 만들고 ( ), something필요하지 않은 사람들을 위해 닫고( 3<&-), 쉘 php가 passthrufd 3에서 stdin을 복원하기 위해 실행 중이라고 알립니다.

예:

$ php -r 'passthru("ls -l /proc/self/fd");'
total 0
lrwx------ 1 stephane stephane 64 Mar 19 15:12 0 -> /dev/pts/38
l-wx------ 1 stephane stephane 64 Mar 19 15:12 1 -> pipe:[22538485]
lrwx------ 1 stephane stephane 64 Mar 19 15:12 2 -> /dev/pts/38

fd 0은 터미널 상호작용에 사용되는 tty 장치입니다.

$ echo hello | php -r 'passthru("ls -l /proc/self/fd");'
total 0
lr-x------ 1 stephane stephane 64 Mar 19 15:12 0 -> pipe:[22539326]
l-wx------ 1 stephane stephane 64 Mar 19 15:12 1 -> pipe:[22530020]
lrwx------ 1 stephane stephane 64 Mar 19 15:12 2 -> /dev/pts/38

stdin은 이제 ls파이프( echo공급)입니다.

$ { echo hello 3<&- | php -r 'passthru("ls -l /proc/\$PPID/fd /proc/self/fd <&3 3<&-");';} 3<&0
/proc/9202/fd:
total 0
lr-x------ 1 stephane stephane 64 Mar 19 15:17 0 -> pipe:[22544619]
lrwx------ 1 stephane stephane 64 Mar 19 15:17 1 -> /dev/pts/38
lrwx------ 1 stephane stephane 64 Mar 19 15:17 2 -> /dev/pts/38
lrwx------ 1 stephane stephane 64 Mar 19 15:17 3 -> /dev/pts/38
lr-x------ 1 stephane stephane 64 Mar 19 15:17 4 -> pipe:[22544623]

/proc/self/fd:
total 0
lrwx------ 1 stephane stephane 64 Mar 19 15:17 0 -> /dev/pts/38
l-wx------ 1 stephane stephane 64 Mar 19 15:17 1 -> pipe:[22544623]
lrwx------ 1 stephane stephane 64 Mar 19 15:17 2 -> /dev/pts/38

lsstdin은 다시 tty 장치가 되었지만 그 상위(php)에는 여전히 stdin에 파이프가 있습니다(fd 3의 tty와 fd 4의 또 다른 파이프, 아마도 lswith 출력을 읽는 파이프 참조).

따라서 여기서 PHP 스크립트를 다음과 같이 변경해야 합니다.

<?php
foreach(file("php://stdin") as $name) {
  echo "Hello $name";
  passthru("nano <&3 3<&-");
}
?>

그리고 그것을 호출하십시오 :

{ printf '%s\n' World Everybody | php script.php; } 3<&0

두 개의 리소스(파이프 printf및 원시 표준 입력)를 php.

php스크립트가 항상 터미널 내에서 호출되도록 하고 nano항상 터미널과 상호 작용해야 하는 경우(그러나 다시 한 번 이렇게 php하면표준 출력 아니요터미널) 다음과 같이 변경할 수 있습니다.

<?php
foreach(file("php://stdin") as $name) {
  echo "Hello $name";
  passthru("nano < /dev/tty");
}
?>

nano우리는 제어 터미널로 stdin을 하드코딩했습니다 .

관련 정보