我正在尝试编写一个以不同间隔运行命令行的分发程序。想想cron,在这里。理想情况下,这将是跨平台的,但cron已存在于* nix中,因此主要用于Windows。
考虑到尝试生成并保持类似守护进程的perl脚本运行的许多问题,我的想法是让操作系统的调度程序每分钟启动脚本并让脚本确定哪些命令行是运行然后这样做。你们中的一些人已经可以看到问题......
如果Windows Scheduler已经在运行,它将不会运行该作业。因此,要运行cron-ish perl脚本,必须在不到一分钟的时间内完成,否则可能会跳过一些预定的命令行。例如,每小时运行一次超过一分钟的事情将使某些事情无法按小时计划运行1分钟。例如,尝试运行此命令的perl程序:
system 1,'perl -e "sleep 10"';
您认为程序会立即返回到命令提示符,其中包含" sleep 10"在Windows中运行'背景...但不,父脚本在退出前等待10秒。
我目前的解决方案是实际循环程序直到所有命令完成...并且每分钟重新进入读取类似crontab的输入的循环。出于各种原因,这是一场噩梦,其中最重要的原因是我的调度程序脚本对它启动的命令感到满意。
有人可能会认为分支系统调用运行每个命令都可行,但在Windows中,父脚本在子项完成之前不会退出。由于一些奇怪的原因,即使命令行使用Windows' start'命令。
我尝试过Win32 :: Process但是它有一些奇怪的限制,主要是它需要一个明确的Windows程序来识别。我在Win32 :: Process周围编写了一个包装器,它在命令行中运行程序,在路径中找到它(也通过使用$ ENV {PATHEXT}查找程序类型...例如,Win32 ::流程不会接受“记事本”,所以我必须确定“notepad.exe”是它想要的,然后在路径中找到它。如果找不到该程序,我认为该程序是$ ENV {COMSPEC}并添加' / c'。所有这些都很有效......直到......
如果我使用这种方法,每当计划中出现一些命令时,Windows就会在我的屏幕上弹出。如果您正在键入电子邮件并且窗口焦点反弹,那么您可能会非常痛苦,因此您会突然输入其他窗口。生产力杀手!
输入开始。使用START / MIN将最小化新流程,因此他们不会在我正在做的事情之上弹出。但是START并不是一个真正的程序,所以试图为我的Win32 :: Process包装器找到它然后默认为$ ENV {COMSPEC}。一切都很好......这样的命令就像" dosomething.pl arg1 arg2"可以重新调整到" cmd / c start / MIN dosomething.pl arg1 arg2"。哪作得好......直到......
...我尝试了像" domsomething.pl arg1 arg2> out.txt"这样的命令。将其更改为" cmd / c start / MIN dosomething.pl arg1 arg2> out.txt"将start的输出发送到out.txt ...这通常都没有(开始就是那么安静)。
另外,我的Win32 :: Process包装器不够精明(如果我避开cmd并启动东西)知道一个命令,例如" dosomething.pl arg1 arg2"需要是" perl -S dosomething.pl arg1 arg2" ...然后perl可以在路径中找到perl.exe。它识别.pl扩展并运行perl的Windows。 Win32 :: Process并没有向Windows询问此类信息,具体取决于我自己解决的问题。我想在某个地方有一个Win32模块可以为我解决这个问题。任何人都知道这是真的吗?
所以,我在这里。没有100%分离进程的好方法...... fork()和" system 1,$ cmd"保持父母一直运行直到孩子们完成。 Win32 :: Process是一个噩梦,可以自动尝试并收集正常工作所需的一切。
有没有人给这只猫剥皮?有什么建议?非常感谢,所有人。
答案 0 :(得分:1)
我剥了这只猫已经有一段时间,但我的笔记说工作流程就像
use Win32::Process;
@cmd = (...); # I think it's ok to begin with START or CMD
my $procObj;
Win32::Process::Create( $procObj, $cmd[0], join(' ',@cmd), 0,
&Win32::Process::DETACHED_PROCESS, "/" )
or die "failed to create detached proc: ",
Win32::FormatMessage( Win32::GetLastError() );
如果你的命令有空格或其他元字符,join(' ',@cmd)
是一个陷阱,那么我们只是说这个问题超出了这个答案的范围。
答案 1 :(得分:0)
这就是我所处的位置......有没有人有更好的主意?
因此,我想要运行的命令是$ cmdline,代码变为:
my $pgm=$ENV{COMSPEC};
$cmdline='/c start /min cmd /c '.$cmdline;
my $flags=DETACHED_PROCESS;
Win32::Process::Create(my $ProcessObj,
$pgm,
$cmdline,
0, # setting this to 1 will make this script wait on this process to end
$flags,
'.', # working dir
);
然后,如果我想从命令中捕获输出,我必须"转义" '>'和'&'人物如此:
$cmdline='pl2 E:\\scripts\\PERLDO_Stuff\\Sums2.perldo ^>e:\\pl2.log 2^>^&1'
(注意:pl2.pl是我的PATH中的perl脚本)
请注意>file.ext
现在^>file.ext
和2>&1
变为2^>^&1
的方式。到目前为止,这是我实现这一目标的唯一方式。
还有其他人对此有任何其他想法吗?