저는 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
출력을 검색하고 전달하는 데 사용되는 파이프이므로 모든 편집자가 그렇지는 않은 것 같습니다) 그렇게 하면 여기에서 사용할 수 있습니다.)php
nano
nano
system()
존재하다:
something | php -r 'passthru("nano");'
이제 php
stdin을 사용하여 파이프를 호출하고 있으며 something
반대쪽 끝에는 stdout이 있습니다. 그리고 nano
그것을 상속받을 것입니다.
php
stdin을 파이프로 만들고 nano
stdin이 쉘의 stdin이 무엇이든 간에 , 어떻게든 해당 리소스를 파이프에 전달하여 php
만들어야 합니다 (또는 php
실행 중인 쉘 passthru
의 표준 입력이 되도록 해야 합니다 ) nano
. 예를 들어 다음과 같이 할 수 있습니다.
{ something 3<&- | php -r 'passthru("nano <&3 3<&-");'; } 3<&0
{...;}
fd 0(stdin)의 리소스를 명령 그룹의 fd 3에서도 사용할 수 있도록 만들고 ( ), something
필요하지 않은 사람들을 위해 닫고( 3<&-
), 쉘 php가 passthru
fd 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
ls
stdin은 다시 tty 장치가 되었지만 그 상위(php)에는 여전히 stdin에 파이프가 있습니다(fd 3의 tty와 fd 4의 또 다른 파이프, 아마도 ls
with 출력을 읽는 파이프 참조).
따라서 여기서 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을 하드코딩했습니다 .