如何在Perl中运行一个脚本并且不等待它完成?

8

我有一个在Perl中的系统调用,看起来像这样:

system('/path/to/utility >> /redirect/to/log file');

但是这需要等待 utility 完成。我只想触发它,让 Perl 脚本完成,无论 utility 调用是否完成。

我该怎么做?

我尝试将该行更改为

system('/path/to/utility >> /redirect/to/log file &');

但是在Windows上,这个语法仍然需要等待调用完成。我需要让它在Linux和Windows上都能正常工作。

4个回答

7
if ($^O eq 'MSWin32') {
   system('start "" \\path\\to\\utility >> \\redirect\\to\\log_file');
} else {
   system('/path/to/utility >> /redirect/to/log_file &');
}

或者

if ($^O eq 'MSWin32') {
   system(1, '\\path\\to\\utility >> \\redirect\\to\\log_file');
} else {
   system('/path/to/utility >> /redirect/to/log_file &');
}

@Lazer,糟糕,它是 system 1,而不是 system -1。(在perlport中有记录。)已修正。 - ikegami

2

你可以尝试查看fork关键字,并在分叉的进程中启动系统命令。请参阅perlipc手册以获取示例。


fork() 在 Windows 上不一定可用。默认情况下,只有在 Perl 运行在 UNIX 平台上时才能使用 UNIX 调用。您可以使用编译器标志构建 Perl,在 Windows 上“模拟” fork() 调用,但谁知道 OPs 的 Perl 是否以这种方式构建? - Mecki
1
我最初对Mecki的评论持敌对态度——fork已经成为Perl每个Windows版本的一部分多年了。但是,在Windows和Unix上的fork之间的一些微妙差异确实与OP有关。在Windows上运行的Perl脚本将不会退出,直到所有fork的子进程完成,这不是OP想要的。简单的脚本fork || sleep 5在Unix中会立即返回,但在Windows中会运行5秒钟。 - mob
@Mecki,fork在Windows上是可用的。它使用线程来模拟。无需编译器标志。 - ikegami

2

在类POSIX系统上最简单的方法实际上是你已经尝试过的方法:

system('/path/to/utility >> /redirect/to/log_file &');

在Windows上让工具在后台执行的最简单方法是使用start.exe作为启动助手:

system('start /path/to/utility >> /redirect/to/log_file');

然而,我不知道将输出重定向到日志文件是否有效,并且此时我周围没有Windows系统进行测试。
是的,这意味着您需要根据当前系统使用代码分支,但其他解决方案也可能需要一个。如果您的Perl具有fork()模拟,则实际上可以在两个系统上使用fork()(这有点更复杂,因为您不能轻易地将stdout重定向到日志文件,您必须先在Perl中打开它并使其成为forked子进程的stdout,然后再调用新进程)。如果您的Windows Perl没有fork()模拟,您还需要一个代码分支,因为在这种情况下,您只能在UNIX上使用fork(),并且您需要在Windows上使用Win32::Process::Create和DETACHED_PROCESS选项。
但也许您可以先告诉我们是否已经成功使用start。如果没有,请注意,start.exe可能无法处理斜杠。在这种情况下,您可能需要使用类似于以下内容的东西。
C:\\path\\to\\utility

替换文本时,请使用双反斜杠(\\),这很重要!单个反斜杠在字符串字面值中有特殊含义;它是转义字符。

要确定您是否在Windows上运行,请查看变量$OSNAME$^OS,它应该在Windows上显示类似于“MSWin32”的内容。


Perl从不将/翻译为\。Windows将/作为目录分隔符接受。这是操作系统本身的特性。Shell和个别命令并不像此那么灵活。有些只有在引号字符串中才接受/ - ikegami
我不认为有任何start.exe--我认为它是内置的--但我现在没有我的Windows机器来检查。 - ikegami
@ikegami:不存在“操作系统本身”这样的东西;在Windows上,有一些系统调用可以接受“/”,但远远不是所有的。我曾经在某个O'Reilly的书中读到过(我想是这样),Perl确实会为一些已知不接受“/”的系统调用进行转换,但这个信息可能是错误的。我会更新我的回复。 - Mecki
@ikegami:不,start不是内置的,它是自己的可执行二进制文件,就像OS X上的“open”一样,至少在Windows XP之前是这样的:http://support.microsoft.com/kb/265016,而且看起来它在Vista中仍然是这样的:http://tinyurl.com/3mwbsml。 - Mecki
"kernel", "API", "Win32", "Win API", "系统调用"它无论被称之为什么,都是存在的,并且支持"/"。 - ikegami
我刚刚检查了一下,在WinXP或Win7上没有start.exe。它是像copydir这样的内置命令。那些链接的页面和你一样犯了同样的错误。 - ikegami

2
这个常见的任务已经被抽象成了 CPAN 模块 Proc::Background

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接