PHP запустить другой скрипт на переднем плане
У меня есть сценарий php, который приводит к запуску другого сценария ожидаемого, передавая ему аргументы.
$output = shell_exec("expect login_script.tcl '$user' '$host' '$port' '$password'");
Использование shell_exec не работает, так как скрипт запускается в фоновом режиме или внутри скрипта php. Мне нужно, чтобы он работал на переднем плане, позволяя пользователю интерактивность. Есть ли элегантный способ сделать это. Уже становится грязно из-за необходимости использовать разные языки сценариев. Я попытался обернуть два сценария сценарием оболочки, который назывался сценарием php, назначил вывод результата в виде переменной (которая была командой) и затем запустил sh. Однако у меня снова возникает та же проблема, когда скрипты запускаются в фоновом режиме, и любая интерактивность пользователя приводит к остановке / зависанию. Это нормально в этой ситуации, если php 'выходит' при вызове shell exec. То есть. php останавливается и ожидает запуска, как если бы вы его называли. (так же, как если бы я просто скопировал выводимую команду и вставил ее в терминал).
Обновление У меня гораздо больше удачи с помощью следующей команды в php:
shell_exec("gnome-terminal -e 'bash -c \"expect ~/commands/login_script.tcl; exec bash\"' &");
Однако можно ли это улучшить, чтобы не закрывать оболочку сразу после завершения вторичного сценария (login_script)?
Дальнейшее обновление
Прочитав ответы, я думаю, что мне нужно уточнить вещи, так как похоже, что люди принимают "более сложную" проблему.
эти два процесса не должны общаться друг с другом, я, вероятно, не должен был ставить
$output = shell_exec
в примере и простоshell_exec
сам по себе, как я считаю, это привело к путанице.Сценарий php должен запускать ожидаемый сценарий только с некоторыми параметрами cli, например, my-script 'param1' 'param2', и его можно считать полностью "асинхронным". Это очень похоже на поведение программ запуска, таких как 'launchy' или 'synapse', они могут запускать другие программы, но не должны влиять на них. Они также не ждут, когда вторичная программа завершит свою работу.
Я сделал ошибку, сказав, что 'shell_exec' не работает для меня. Я должен был сказать, что "мне пока не удалось использовать shell_exec", но
shell_exec("gnome-terminal -e 'bash -c \"expect ~/commands/login_script.tcl; exec bash\"' &");
"работает", но все еще пытается найти правильную комбинацию кавычек, чтобы разрешить передачу аргументов ожидаемому сценарию.
4 ответа
Управление задачами - интересная, но сложная работа.
Поскольку ваш пользователь может перемещаться во время задачи (и приводит к неожиданному результату, такому как зависание сеанса или незавершенная работа процесса), вам необходимо выполнить его в фоновом режиме. Если вам нужно взаимодействовать между вашим пользователем и вашим процессом, вам нужно создать способ общения.
Самым простым способом (я думаю) является использование файла, который используется совместно с вашим пользовательским сеансом и задачей.
Если у вас много пользователей одновременно и много взаимодействует между пользователем и процессами, вы можете смонтировать раздел в памяти для оптимизации операций чтения / записи.
В вашем fstab такая строка:
tmpfs /memory tmpfs defaults,uid=www-data,gid=www-data,size=128M 0 0
Или, в сценарии, вы можете сделать:
#!/bin/sh
mkfs -t ext2 -q /dev/ram1 65536
[ ! -d /memory ] && mkdir -p /memory
mount /dev/ram1 /memory
chmod -R 777 /memory
Вам нужно будет позаботиться о многих вещах:
- доступ к файлу (чтобы избежать параллелизма между вашим веб-приложением и вашими процессами)
- время (чтобы избежать зомби или бесполезных длительных сценариев)
- безопасность (такие операции должны быть тщательно продуманы)
- управление ресурсами (чтобы избежать одновременного запуска 10000 процессов)
- ...
Я думаю, что вы ищете, это команда proc_open(). Это дает вам доступ к потокам stdin/stdout фонового процесса. Вы можете передать свои собственные потоки stdin/stdout новому процессу в параметре $descriptorSpec, который позволит фоновому процессу общаться с пользователем.
Вашему приложению 'переднего плана' придется подождать, пока не прекратится фоновый процесс. Я на самом деле не сделал этого с PHP, но я предполагаю, что вам придется смотреть $pipe, чтобы увидеть, когда они закроются - тогда вы будете знать, что фоновый процесс завершен, и вы можете удалить ресурс процесса и продолжайте с тем, что должен делать процесс переднего плана.
В конце концов мне удалось заставить его работать, добавив третий тип кавычки: ` (я полагаю, это называется 'галс'?), Который позволил мне передать аргументы следующему сценарию из первого сценария.
Команда, в которой я нуждался в моем сценарии php, была:
$command = `gnome-terminal -e 'bash -c "expect ~/commands/login_script.tcl \"$user\" \"$host\" \"$port\" \"$password\"; exec bash"' &`;
shell_exec($command);
Потребовалось некоторое время, чтобы все цитаты были правильными, поскольку изменение типа кавычек может привести к тому, что он не будет работать.
Использование:
pcntl_exec("command", array("parameter1", "parameter2"));
Например, у меня есть скрипт, который запускает команду mysql с использованием параметров в текущем проекте php, который выглядит следующим образом:
pcntl_exec("/usr/bin/mysql", array(
"--user=".$params['user'],
"--password=".$params['password'],
"--host=".$params['host'],
$params['dbname']
));
Это не зависит от терминала gnome или чего-либо еще, оно заменяет PHP программой, которую вы вызываете.
Вам нужно знать полный путь к команде, что является проблемой, поскольку она может варьироваться в зависимости от платформы, но вы можете использовать env
команда команда, которая доступна в /usr/bin/env
на большинстве систем, чтобы найти команду для вас. Приведенный выше пример становится:
pcntl_exec("/usr/bin/env", array(
"mysql",
"--user=".$params['user'],
"--password=".$params['password'],
"--host=".$params['host'],
$params['dbname']
));