#!/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-command,但它不起作用:
找不到shell的绝对路径:&
使它运作的正确方法是什么?
答案 0 :(得分:19)
Perl的system函数有两种模式:
在第一种形式中,您必须小心转义可能对shell有特殊含义的字符。第二种形式通常更安全,因为参数直接传递给正在执行的程序,而不涉及shell。
在你的情况下,你似乎混合了两种形式。如果将&
字符传递给shell,则其仅具有“在后台启动此程序”的含义。在你的程序中,&符号作为xterm命令的第5个参数传递。
正如Jakob Kruse所说,简单的答案是使用system
的单字符串形式。如果任何参数来自不受信任的来源,您必须使用引用或转义来使它们安全。
答案 1 :(得分:12)
请注意,system的列表形式特别针对而不是将&
等字符视为shell元字符。
从perlfaq8回答How do I start a process in the background?
(由brian d foy提供)
没有一种方法可以在后台运行代码,因此在程序转移到其他任务之前,您无需等待它完成。流程管理取决于您的特定操作系统,许多技术都在perlipc中。
多个CPAN模块可能会提供帮助,包括IPC::Open2或IPC::Open3,IPC::Run,Parallel::Jobs,Parallel::ForkManager,POE,{ {3}}和Proc::Background。您可以使用许多其他模块,因此请检查这些名称空间以获取其他选项。
如果您使用的是类Unix系统,那么您可以通过系统调用来放弃一个&在命令的末尾:
system("cmd &")
您也可以尝试使用fork,如perlfunc中所述(尽管这与许多模块将为您做的事情相同)。
STDIN,STDOUT和STDERR是共享的
主进程和后台进程(“子进程”)共享相同的STDIN,STDOUT和STDERR文件句柄。如果两者都试图立即访问它们,可能会发生奇怪的事情。您可能想为孩子关闭或重新打开这些。您可以通过打开管道来解决这个问题(请参阅在perlfunc中打开),但在某些系统上,这意味着子进程不能超过父进程。 信号 你必须捕获SIGCHLD信号,也可能是SIGPIPE。在后台进程完成时发送SIGCHLD。当您写入子进程已关闭的文件句柄时,会发送SIGPIPE(未处理的SIGPIPE会导致程序无声地死亡)。这不是系统的问题(“cmd&”)。
僵尸
你必须准备在完成后“收获”子进程。
$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);
请参阅Win32::Process中的信号,了解执行此操作的其他代码示例。僵尸不是系统的问题(“prog&”)。
答案 2 :(得分:4)
你试过吗?
system('xterm -geometry 80x25-5-5 -bg green &');
http://www.rocketaware.com/perl/perlfaq8/How_do_I_start_a_process_in_the_.htm
答案 3 :(得分:0)
这不仅仅是对Perl的解释。同样的问题是在C和其他语言下。
首先了解系统命令的作用:
如果传递多个参数或一个参数,则无关紧要。不同之处在于,使用多个参数,命令将直接执行。使用一个参数,命令由shell包装,最后执行为:
/bin/sh -c your_command_with_redirections_and_ambersand
当您将命令作为 some_command par1 par2& 传递时,Perl解释器和命令之间是 sh 或 bash 进程用作包装器,它正在等待 some_command 完成。您的脚本正在等待shell解释器,并且不需要额外的 waitpid ,因为Perl的函数 system 为您完成。
如果要直接在脚本中实现此机制,则应该:
if
)下,使用exec
功能。您的用户与系统类似,请参阅手册。注意,exec
通过执行的命令导致子进程程序/内容/数据覆盖。这就是您可以在后台运行该过程的原因。我希望这很简单。
最简单的例子:
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
}