Как я могу запускать системные команды Perl в фоновом режиме?

#!/usr/bin/env perl
use warnings; use strict;
use 5.012;
use IPC::System::Simple qw(system);

system( 'xterm', '-geometry', '80x25-5-5', '-bg', 'green', '&' );

say "Hello";
say "World";

Я попытался запустить xterm-команду в фоновом режиме, но она не работает:

не найден абсолютный путь для shell: &

каков был бы правильный способ заставить его работать?

4 ответов



обратите внимание, что форма списка система создана специально для не лечить такие символы, как & как метасимволы оболочки.

С perlfaq8ответом как запустить процесс в фоновом режиме?


(Автор Брайан Д Фой)

нет ни одного способа запустить код в фоновом режиме, поэтому вам не нужно ждать его завершения, прежде чем ваша программа перемещается к другим задачам. Управление процессом зависит от конкретной операционной системы, и многие из методов в perlipc.

несколько модулей CPAN могут помочь, включая IPC:: Open2 или IPC:: Open3, IPC:: Run, Parallel:: Jobs, Parallel:: ForkManager, Гэ, Proc:: Background и С Win32::Процесс. Есть много других модулей, которые вы можете использовать, так что проверьте эти пространства имен для других опций тоже.

если вы находитесь в Unix-подобной системе, вы можете уйти с системным вызовом, где вы помещаете & в конец команды:

system("cmd &")

вы также можете попробовать использовать fork, как описано в perlfunc (хотя это то же самое, что многие модули будут делать для вас).

stdin, STDOUT и STDERR являются общими

как основной процесс, так и фоновый ("ребенок" процесс) разделяют те же stdin, STDOUT и stderr filehandles. Если оба попытаются получить к ним доступ одновременно, могут произойти странные вещи. Вы можете закрыть или открыть их для ребенка. Вы можете обойти это, открыв канал (см. open в perlfunc), но в некоторых системах это означает, что дочерний процесс не может пережить Родительский. Сигналы Вы должны поймать сигнал SIGCHLD, и, возможно, SIGPIPE тоже. SIGCHLD отправляется после завершения процесса backgrounded. SIGPIPE отправляется, когда вы пишете filehandle, дочерний процесс которого закрыт (незахваченный SIGPIPE может заставить вашу программу тихо умереть). Это не проблема с системой("КИПиА").

зомби

вы должны быть готовы "пожинать" дочерний процесс, когда он заканчивается.

$SIG{CHLD} = sub { wait };

$SIG{CHLD} = 'IGNORE';

вы также можете использовать двойной вилкой. Вы немедленно ждете() своего первого ребенка, и демон init будет ждать () вашего внука, как только он выйдет.

unless ($pid = fork) {
    unless (fork) {
        exec "what you really wanna do";
        die "exec failed!";
    }
    exit 0;
}
waitpid($pid, 0);

посмотреть сигналы в perlipc для других примеров кода, чтобы сделать это. Зомби не проблема с системой ("prog&").


вы пробовали?

system('xterm -geometry 80x25-5-5 -bg green &');

http://www.rocketaware.com/perl/perlfaq8/How_do_I_start_a_process_in_the_.htm


Это не просто объяснение для Perl. Такая же проблема на C и других языках.

сначала поймите, что такое система тут:

  1. вилки
  2. при вызове дочернего процесса exec
  3. родительский процесс ожидает завершения раздвоенного дочернего процесса

не имеет значения, передаете ли вы несколько аргументов или один аргумент. Разница в том, что с несколькими аргументы, команда выполняется напрямую. С одним аргументом команда обертывается оболочкой и, наконец, выполняется как:

/bin/sh -c your_command_with_redirections_and_ambersand

когда вы передаете команду some_command par1 par2&, затем между интерпретатором Perl и командой находится ш или Баш процесс используется в качестве обертки, и он ждет some_command отделочные работы. Ваш скрипт ждет интерпретатора оболочки, и никаких дополнительных С помощью waitpid необходимо, потому что функция Perl система делает это для вас.

если вы хотите реализовать этот механизм непосредственно в своем скрипте, вы должны:

  1. использовать вилки. Ваш пользователь похож на система обратитесь к руководству. Заметьте,exec вызывает дочернюю программу процесса / контент / покрытие данных выполняемой командой.
  2. при родительском условии (если, fork выходит с ненулевым), вы используете waitpid, используя pid, возвращаемый функцией fork.

именно поэтому вы можете запустить процесс в фоновом режиме. Надеюсь, все просто.

простейший пример:

if (my $pid = fork) { #exits 0 = false for child process, at this point is brain split
  # parent ($pid is process id of child)
  # Do something what you want, asynchronously with executed command
  waitpid($pid);  # Wait until child ends
  # If you don't want to, don't wait. Your process ends, and then the child process will be relinked
  # from your script to INIT process, and finally INIT will assume the child finishing.
  # Alternatively, you can handle the SIGCHLD signal in your script
}
else {
  # Child
  exec('some_command arg1 arg2'); #or exec('some_command','arg1','arg2');
  #exit is not needed, because exec completely overwrites the process content
}