【问题标题】:How to run a script and not wait for it in Perl?如何在 Perl 中运行脚本而不是等待它?
【发布时间】:2011-11-15 12:31:48
【问题描述】:

我在 Perl 中有一个如下所示的系统调用:

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

但这要等待utility 完成。我只想触发它并让 Perl 脚本完成,而不管 utility 调用是否完成。

我该怎么做?

我尝试将行更改为

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

但此语法仍在 Windows 上等待调用完成。我需要让它在 Linux 和 Windows 上运行。

【问题讨论】:

    标签: perl cross-platform platform-independent


    【解决方案1】:
    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 中。)已修复。
    【解决方案2】:

    您可以尝试查看fork 关键字,然后从分叉的进程中启动您的系统命令。有关示例,请参见 perlipc 手册页。

    【讨论】:

    • fork() 在 Windows 上不一定可用。默认情况下,只有当 Perl 在 UNIX 平台上运行时,UNIX 调用才可用。您可以使用编译器标志构建 Perl 以“模拟”Windows 上的 fork() 调用,但谁知道 OPs Perl 是否是这样构建的?
    • 我最初对 Mecki 的评论持敌意——fork 多年来一直是 Perl 的每个 Windows 构建的一部分。但是 Windows 和 Unix 上的 fork 之间的一些细微差别确实对 OP 有影响。在所有forked 孩子完成之前,Windows 上的 Perl 脚本不会退出,这不是 OP 想要的。简单的脚本fork || sleep 5 在 Unix 中会立即返回,但在 Windows 中会运行 5 秒。
    • @Mecki, fork 在 Windows 上可用。它是使用线程模拟的。不需要编译器标志。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      在类 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()(这有点复杂,因为你不能那么容易地将标准输出重定向到日志文件,你首先必须在 Perl 中打开它并制作它在调用新进程之前分叉子的标准输出)。如果您的 Windows Perl 没有 fork() 仿真,您还需要一个代码分支,因为在这种情况下,您只能在 UNIX 上使用 fork(),而您需要在 Windows 上使用 Win32::Process::CreateDETACHED_PROCESS 选项。

      但也许您可以先让我们知道使用 start 是否对您有用。如果没有,可能start.exe 不处理斜线。在这种情况下,您可能必须使用类似

      C:\\path\\to\\utility
      

      相反(双反斜杠很重要!单个反斜杠在字符串文字中具有特殊含义;它是转义字符)。

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

      【讨论】:

      • Perl 从不将/ 转换为\ 。 Windows 接受/ 作为目录分隔符。这就是操作系统本身。 shell 和单独的命令不需要那么灵活。有些人只接受 / 在引号字符串中。
      • 我不认为有任何 start.exe -- 我认为它是内置的 -- 但我不在我的 Windows 机器上检查。
      • @ikegami:没有所谓的“操作系统本身”;在 Windows 上有几个接受 / 的系统调用,但到目前为止还不是全部。我在某处(我认为是在 O'Reilly 的书中)读到 Perl 确实为一些已知不接受 / 的系统调用翻译了它,但这些信息当然可能是错误的。我会更新我的回复。
      • @ikegami:不,start 不是内置的,它是一个自己的可执行二进制文件,如 OS X 上的“open”,至少它取决于 Windows XP:support.microsoft.com/kb/265016,它看起来喜欢它还在 Vista 中:tinyurl.com/3mwbsml
      • "kernel", "API", "Win32", "Win API", "system calls" 你想怎么称呼它,但它确实存在,并且它接受/。跨度>
      猜你喜欢
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      • 1970-01-01
      • 1970-01-01
      • 2011-02-08
      相关资源
      最近更新 更多