如何在MATLAB中执行DOS命令并立即将控制返回给MATLAB(而不生成DOS窗口)

8

我希望能够在MATLAB中执行一个批处理文件,并且立即将控制权返回给MATLAB。但是,我希望在此过程中不打开DOS窗口(或者至少在结束时关闭DOS窗口)。

如果我像这样格式化我的命令...

s = dos('batchfilename.bat');

然后MATLAB运行批处理文件时不会打开DOS窗口,但是MATLAB代码必须等待返回。

如果我按照以下格式编写命令...

s = dos('batchfilename.bat &');

控制权立即返回给MATLAB,但它也显示了我不想要的dos窗口。(当你以这种方式做时,检测批处理文件何时“完成”也很困难)

如果有任何帮助将不胜感激。


1
@Jonas:你可能链接了错误的答案?那个与子进程无关。 - Ben Voigt
@BenVoigt:抱歉,答案是对的,问题错了 :) - Jonas
2个回答

8

使用Matlab的外部接口支持来访问低级语言的进程控制功能。

.NET版本

使用.NET System.Diagnostics.Process类。它可以让您异步运行进程,检查其何时退出并收集退出代码。您还可以选择隐藏其窗口或保留其可见性以进行调试。

您可以直接从M代码调用.NET类。

function launch_a_bat_file()
%//LAUNCH_A_BAT_FYLE Run a bat file with asynchronous process control

batFile = 'c:\temp\example.bat';
startInfo = System.Diagnostics.ProcessStartInfo('cmd.exe', sprintf('/c "%s"', batFile));
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;  %// if you want it invisible
proc = System.Diagnostics.Process.Start(startInfo);
if isempty(proc)
    error('Failed to launch process');
end
while true
    if proc.HasExited
        fprintf('\nProcess exited with status %d\n', proc.ExitCode);
        break
    end
    fprintf('.');
    pause(.1);
end

Java版本

.NET版本需要一个支持.NET的新版Matlab。这里提供一个基于Java的版本,适用于像OP这样的旧版Matlab。稍作修改后也可以在非Windows系统上使用。

function launch_a_bat_file_with_java
%LAUNCH_A_BAT_FILE_WITH_JAVA  Java-based version for old Matlab versions

batFile = 'c:\temp\example.bat';
cmd = sprintf('cmd.exe /c "%s"', batFile);
runtime = java.lang.Runtime.getRuntime();
proc = runtime.exec(cmd);

while true
    try
        exitCode = proc.exitValue();
        fprintf('\nProcess exited with status %d\n', exitCode);
        break;
    catch
        err = lasterror(); % old syntax for compatibility
        if strfind(err.message, 'process has not exited')
            fprintf('.');
            pause(.1);
        else
            rethrow(err);
        end
    end
end

在Java版本中,您可能需要调整I/O以避免挂起启动的进程;demarcmj指出,您需要读取并刷新进程的输入流以避免stdout填满。


对我来说,在R2009b上可以工作。Matlab 7.1已经过时了,那是从2005年中期开始的。在那个时候,甚至还没有发布.NET 2.0。自那时以来,Matlab的外部接口(其中包括.NET支持)和全新的面向对象系统都进行了大量的工作。你应该考虑升级。SO上一半的其他答案可能也无法在7.1上运行。 - Andrew Janke
不幸的是,升级不是一个选项。我猜我只能在我的GUI中添加一个按钮来使进度指示成为按需操作。这并不理想,但这是我能做到的最好的。 - demarcmj
哎呀,7.1 版本的 JVM 是什么?(ver 命令可以列出版本信息。)Java 1.3 或更新版本中的 java.lang.Runtime.execjava.lang.Process 类提供了类似但更粗略的异步进程控制方式,并且也可以直接从 M 代码中调用。还可以让你获取标准输入和输出作为 I/O 流。 - Andrew Janke
1
如果有人在未来阅读这篇文章... 显然,proc对象具有缓冲输入和输出流,如果您不注意它们,可能会导致在Runtime.exec()中永远挂起的问题。为了防止这种情况,我需要在“while”上方添加“a = proc.getInputStream;”和“b = getOutputStream;”,并在“while”下方添加“a.read;b.flush;”(在每个while循环迭代的开头)。 - demarcmj
这个线程对我来说是一个救命稻草,帮助我编写了一小段代码来自动化通过matlab运行模拟。我使用的是.NET版本,它完美地工作。我想在Linux机器(CentOS7)上运行相同的代码,但是当尝试使用.NET的System.Diagnostics.ProcessStartInfo类时出现错误。当涉及到Linux和在Linux上使用MATLAB时,我是一个初学者。解决方案是否就像在这台Linux计算机上安装.NET那么简单,还是还有其他需要注意的事情? - DonaldH
显示剩余5条评论

3
尝试使用Windows命令解释器捆绑的start cmdlet。您可能只需要执行system('start /MIN batchfilename.bat');。在批处理文件的末尾放置一个exit命令,以确保您不会留下一个(最小化的)命令提示符。

可能会起作用(我得试一试然后回报告)。我确实看到一个潜在的缺陷,就是它没有给你返回值。 - demarcmj
@demarcmj:嗯,当system返回时没有退出代码,因为您的MatLab代码继续运行而不等待子进程。实际上,您可以从start获取返回代码,这可能会告诉您批处理文件未找到。如果您想生成一个子进程,然后稍后查询其完成和退出代码,则可能需要使用MEX和一些Win32 API函数,例如CreateProcess - Ben Voigt
在这种情况下,我可能只能使用“s = dos('batchfilename.bat');”形式,以便获得正确的返回值,因为我需要它,不想在那里处理任何其他东西。我想我的唯一方法在执行时“做事情”将是在我的GUI中添加一个单独的按钮,这并不理想,但可以完成工作。 - demarcmj
您还可以直接从 M 代码调用 .NET 的 System.Diagnostics.Process。与在 MEX 中使用 CreateProcess 相比,这可能更容易编写,并且它公开了 ExitCode。http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx - Andrew Janke

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