パイプがスクリプトのサブシェルに流れ込むのを防ぐ方法

パイプがスクリプトのサブシェルに流れ込むのを防ぐ方法

私は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");'

php私はstdinを使ってパイプを呼び出していて、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

2つのリソース(パイプprintfと生の標準入力)をphp

このphpスクリプトが常に端末内で呼び出されるようにし、nano常に端末と対話する必要がある場合(ただし、もう一度これを行うphp標準出力 いいえターミナル) 次のように変更できます。

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

nano私たちは制御端末でstdinをハードコードしました。

おすすめ記事