如何让 MATLAB 的系统() 或 dos() 实时显示控制台输出?

How can I get MATLAB's system() or dos() to show the console output in real time?

本文关键字:显示 实时 控制台 输出 dos MATLAB 系统      更新时间:2023-10-16

我有一个 MATLAB 脚本,它使用 system() 命令调用可执行文件(用 C++ 编写),如下所示:

exe_status = system('MySimulation.exe', arguments);

由于可执行文件可能需要相当长的时间才能运行(最多几个小时),因此我在其中包含一个函数,该函数估计剩余时间并将其输出到控制台。 如果我在 MATLAB 外部运行可执行文件,Windows 控制台大致如下所示:

Simulation #B01 initiated...
Completion: 0.57%    Time remaining: 183 m 2 s

使用r字符,"完成"行每秒重写一次。 这非常有效,让我知道何时回来分析数据。

遗憾的是,从 MATLAB 控制台调用可执行文件的效果并不相同。 MATLAB 会等到可执行文件终止后再显示任何控制台输出,从而使我的计时器毫无意义。

我尝试了以下命令,但它们都具有相同的行为:

exe_status = system('MySimulation.exe', arguments);
exe_status = system('MySimulation.exe', arguments, '-echo');
exe_status = dos('MySimulation.exe', arguments);
exe_status = dos('MySimulation.exe', arguments, '-echo');

除非我读错了,否则 MATLAB 文档似乎表明'-echo'可用于在可执行文件仍在运行时回显命令输出,但它对我的特定程序没有影响。

我很好奇,所以我尝试了一些东西。我尝试了一个 bash 脚本、一个 c 可执行文件和一个 python 脚本,它们都"实时"显示它们的输出 Matlab 命令窗口,这是问题所需的行为。我无法重现问题中描述的情况。

所以我怀疑:

a) 无论您使用哪种方法叠印同一行,都是问题所在。它可能不是使用r,它可能与您在C++可执行文件中使用的特定打印方法有关。我会尽量不使用叠印,而只是使用您能想到的最简单的打印语句在新行上打印状态。

b) 该问题特定于操作系统。

为了完整起见,以下是有关我尝试的内容和结果(环境和打印语句)的详细信息:

  1. bash脚本; echo ""
  2. 编译的 C 代码; printf("n")
  3. 蟒蛇 2.7 脚本; print("".format() )
  4. 操作系统内置 ping 程序(如注释中所述)

我在 Matlab 中使用 system 命令运行了它,例如 system('./timer_out'); .在所有情况下:

-

如果没有第二个输出变量,则打印输出"实时"显示,无论使用"-echo"标志还是尾随分号,例如:

tic; system('./timer_out'); toc

-如果给定输出变量,则抑制打印输出,例如:

tic; [s,r]=system('./timer_out'); toc
-

如果给定输出变量并使用"-echo"标志,则实时显示打印输出,例如:

tic; [s,r]=system('./timer_out','-echo'); toc

此行为符合文档。这些测试在OS X上使用Matlab R2015b。

我想我最初的问题措辞太字面了 - 我通过修改C++代码而不是 MATLAB 代码找到了解决方案。 具体来说,我在控制台打印命令的末尾添加了std::endlstd::flush,如下所示:

std::cout << "Simulation #B01 initiated..." << std::endl;

我的猜测是,刷新流会提示 MATLAB "实时"(或多或少)向控制台显示流的内容,这是 Windows 控制台在具有特定操作系统的特定计算机上不需要的,等等。 我敢肯定,这里有一堂关于可移植性的生活课,但我对自己正在做的事情知之甚少,无法正确构建它。

作为旁注,我注意到 MATLAB 无法正确识别控制台中r的回车符。 为了防止我的可执行文件向控制台发送可能数千行更新状态的垃圾邮件,我替换了旧的更新行函数

void time_remaining( ... ) {
    std::string completion_update = ( ... );
    std::cout << completion_update << "r";
}

用稍微复杂的一个

int time_remaining( string_length, ... ) {
    for(i = 0; i < string_length; i++) std::cout << "b";
    std::string completion_update = ( ... );
    std::cout << completion_update << std::flush;
    string_length = completion_update.length();
    return string_length;
}

它依赖于退格字符b和字符串completion_update的先前迭代的字符长度。