1

我有一个包含此代码片段的 Perl 脚本,它调用系统 shell 通过 SFTP 获取一些文件并使用 WinZip 解压缩它们:

#  Run script to get files from remote server
system "exec_SFTP.vbs";

#  Unzip any files that were retrieved
foreach $zipFile (<*.zip>) {
    system "wzunzip $zipFile";
}

即使检索到某些文件,它们也永远不会解压缩,因为在检索文件并关闭 SFTP 连接时,Perl 脚本已经完成了解压缩步骤,结果它找不到任何要解压缩的内容。

我的短期解决办法是插入

sleep(60);

在解压缩步骤之前,但假设 SFTP 连接将在 60 秒内完成,这有时可能会被严重高估,有时可能被低估。

在继续解压缩步骤之前,是否有更合理的方法可以让 Perl 暂停,直到 SFTP 连接关闭?

编辑:响应者质疑(并且合理地如此)使用 VB 脚本而不是让 Perl 进行文件传输。它与安全有关——VB 脚本由其他人维护,并被授权执行 SFTP。

4

8 回答 8

12

检查 *.vbs 文件中的代码。该system函数在继续执行之前等待子进程完成。看来您的 *.vbs 文件正在分叉一个后台任务来执行 FTP 并立即返回。

于 2009-05-19T19:54:27.230 回答
6

在一个完美的世界中,您的脚本将被重写以使用Net::SFTP::ForeignArchive::Extract ..

一种丑陋的快速破解方法可能是在您的第一次系统调用之前创建一个触摸文件,更改您的 sftp-fetching 脚本以在完成后删除文件并有一段时间像这样

while(-e 'touch.file') {
    sleep 5;
}

# foreach [...]

当然,如果您的 .vbs 失败并留下未删除的 touchfile 以及许多其他不良副作用,您需要小心。这将是一个快速解决方案(如果其他建议都不起作用),直到您有时间在没有 system() 调用的情况下进行重写。

于 2009-05-19T20:16:51.677 回答
4

您需要一种方法让 Perl 等到 SFTP 传输完成,但由于您的脚本当前正在编写,Perl 无法知道这一点。(看起来您至少结合了两种脚本语言和一个(GUI?)SFTP 客户端;这可以工作,但它并不完全可靠或健壮。为什么使用 VBscript 来启动 SFTP 传输?)

我可以想到四个选项:

  1. 您的 Perl 脚本可以自己进行 SFTP 传输,使用 CPAN 的Net::SFTP模块之类的东西,而不是生成无法跟踪其状态的外部作业。
  2. 您的 Perl 脚本可能会生成一个命令行 SFTP 实用程序(如PSFTP),该实用程序在传输完成之前不会返回。
  3. 或者将 exec_SFTP.vbs 脚本更改为在传输完成之前不返回。
  4. 如果您当前使用的是图形 SFTP 客户端并且由于某种原因无法切换,我建议您使用AutoIt之类的脚本语言而不是 Perl。AutoIt 具有等待窗口更改状态等功能,因此它可以更轻松地监控活动的完成情况。

选项 1 或 2 将是最稳健和最可靠的。

于 2009-05-19T19:54:34.733 回答
3

我可以建议的最好的方法是修改 exec_SFTP.vbs 以仅在文件传输完成后退出。 system 等待它调用的程序完成,这样应该可以解决您的问题:

       系统列表
       系统程序列表
               与“exec LIST”完全相同,除了
               先做一个分叉,然后是父进程
               等待子进程完成
于 2009-05-19T19:56:29.143 回答
2

如果您无法修改 vbs 脚本以使其在终止之前保持活动状态,则您可以跟踪子进程的创建。如果您获得子进程 ID,则可以监视它们,从而知道 vbs 的各种后代何时终止。

Win32::Process::Info允许您从正在运行的进程中获取子进程 ID。

于 2009-05-19T21:27:55.933 回答
1

也许这是一个愚蠢的问题,但为什么不直接使用Net::SFTPArchive::Extract Perl 模块来下载和解压缩文件呢?

于 2009-05-19T20:03:12.937 回答
0

看看IPC::Open3

IPC::Open3 - 使用 open3() 打开一个用于读取、写入和错误处理的进程

于 2009-05-19T19:52:05.080 回答
0

system在运行命令的 shell 返回之前不会返回;这对于启动图形程序和文件关联可能是错误的。

看看有没有以下帮助?

system('cscript exec_SFTP.vbs');

use Win32::Process;
use Win32;
Win32::Process::Create(my $proc, 'wscript.exe',
        'wscript exec_SFTP.vbs', 0, NORMAL_PRIORITY_CLASS, '.');
$proc->Wait(INFINITE);
于 2009-05-19T20:00:10.273 回答