Как предотвратить попадание конвейера во вспомогательную оболочку в сценарии

Найдено решение с использованием этого обходного пути

Преобразование аргументов QEMU в XML домена

После преобразования в импорт XML с помощью

virsh create file.xml

1
19.03.2018, 17:25
1 ответ

Да, процессы наследуют файловые дескрипторы своего родителя, когда вы это делаете:

В

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

phpунаследует стандартный ввод оболочки (устройство tty, если оно вызывается по приглашению интерактивной оболочки )и nanoтакже унаследует его (, а стандартный вывод — это канал, используемый phpчтобы получить вывод nanoи передать его, nano, кажется, доволен этим, не все редакторы, вы можете использовать system()вместо этого здесь ).

В:

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

Вы вызываете phpс его stdin теперь канал с somethingstdout на другом конце. И nanoунаследует его.

Если вы хотите, чтобы stdin phpбыл каналом, а nanostdin каким бы ни был stdin оболочки, вам нужно каким-то образом передать этот ресурс на phpи иметьphp(или оболочку запускаемыйpassthru)сделать его стандартным для nano.Это можно сделать, например, с помощью:

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

Где мы делаем ресурс на fd 0 (stdin )также доступным на fd 3 в группе команд ({...;}), закрываем его для something, которому он не нужен (3<&-), и сообщаем оболочка, запускаемая php passthruдля восстановления stdin из этого fd 3.

Пример:

$ 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 (см. также tty на fd 3 и еще один канал на fd 4, вероятно, тот он читает вывод lsс помощью ).

Итак, здесь вам нужно изменить ваш 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");
}
?>

Где мы жестко -кодируем nanostdin как управляющий терминал.

1
27.01.2020, 23:43

Теги

Похожие вопросы