【问题标题】:How to run Windows Commands through C++ Program?如何通过 C++ 程序运行 Windows 命令?
【发布时间】:2017-06-14 20:35:35
【问题描述】:

对于一些帮助你们的信息,我正在制作一个小程序,它将获取一个 .SQL 文件并使用 mysql.exe 将其恢复到用户 localhost phpMyAdmin。手动通过 MyAdmin 本身导入文件需要很长时间,因为它必须解压缩和解析信息,这种方法更快,而且它适用于我的同事,因为我们总是将备份和恢复推送到我们的 WAMP 进行试验。

我面临的一个问题是,无论如何我似乎都无法让它更改目录。我知道可执行文件在哪里启动就是系统将继承的路径,那我为什么不能简单地告诉它改变目录呢?

到目前为止,这是我的代码:

system("cd c:\wamp64\bin\mysql\mysql5.7.14\bin");
system("PAUSE");
system("dir");
system("PAUSE");
system("mysql.exe -u root -p dataBase < tables.sql");

注意:暂停和 system("dir") 在那里严格用于测试目的,一旦窗口吐回目录的正确内容,我就知道它有效,我只有第一个和最后一个程序中剩下的行。

更新:我被告知每次调用 system 都会创建一个新的 CMD 进程,这完全可以解释为什么 cd 不会影响任何东西,因为它正在打开一个新进程,更改目录,然后在下一行它正在调用一个新进程并暂停它。解决方法是什么?

更新 2:我决定使用 && 将多个命令连接在一起,但这限制了我的可用性和“样式”方面,但这不是问题,需要该程序作为运行& 完成的交易类型。

这是我想出的:

system("cd c:\\wamp64\\bin\\mysql\\mysql5.7.14\\bin && mysql.exe -u root -p dataBase < table.sql");
cout << "\n" << "The database 'dataBase' has been restored using 'table.sql' successfully!" << "\n\n";
return 0;

创建 .cmd 文件并使用 CreateProcess() 运行它有什么好处,或者使用我想出的方法有什么坏处吗?

注意:数据库名称和 .sql 文件不是从任何东西中提取的,名称将是静态的,因此我不必担心更新。

【问题讨论】:

  • 不要使用system。它有很多,所以,很多问题......
  • 1.您没有收到有关不良转义序列的警告吗? 2.每次调用系统都会打开一个新的命令会话。因此cd没有效果。
  • 解决方法是什么?在一个 system() 调用中完成所有操作。
  • 在您的 cmd.exe 参考中查找 &&。

标签: c++


【解决方案1】:

更好的办法是动态生成一个批处理文件(.cmd.batthere are slight differences),然后使用cmd.exe /c batchFile.cmd 调用它:

#include <cstdlib>
#include <cstdio>

ofstream batch_file;
batch_file.open( "commands.cmd", ios::trunc );
batch_file <<
    "cd c:\\wamp64\\bin\\mysql\\mysql5.7.14\\bin" << endl <<
    "PAUSE" << endl <<
    "dir" << endl <<
    "PAUSE" << endl <<
    "mysql.exe -u root -p dataBase < tables.sql" << endl;
batch_file.close();

int batch_exit_code = system( "cmd.exe /c commands.cmd" ); // blocks until the child process is terminated
if( batch_exit_code != 0 ) {
    cout << "Batch file exited with code " << batch_exit_code << endl;
}

remove( "commands.cmd" ); // delete the batch file

这样做的好处是允许您自定义文本和命令,例如执行您自己的 MySQL 二进制文件和临时文件的位置检测。

请注意,如果您始终在 Windows 上运行,您可能希望使用 CreateProcess,因为 system 有一些开销:

system() and CreateProcess() / CreateProcessW()

系统函数将命令传递给命令解释器,命令解释器将字符串作为操作系统命令执行。 system 指的是 COMSPEC 和 PATH 环境变量,用于定位命令解释器文件(Windows NT 中名为 CMD.EXE 的文件)。

因为你想直接运行cmd.exe,这会导致它打开两次。

您可以改用CreateProcess

STARTUPINFO info={sizeof(info)};
PROCESS_INFORMATION processInfo;
if( CreateProcess( "cmd.exe", "/c commands.cmd", NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo ) )
{
    WaitForSingleObject( processInfo.hProcess, INFINITE );
    CloseHandle( processInfo.hProcess );
    CloseHandle( processInfo.hThread );
}

【讨论】:

  • 很好的信息!我阅读了 CreateProcess,似乎比调用系统打开系统更可行。现在这不会导致问题,因为该 command.cmd 文件将始终保留吗?还是每次迭代都会简单地覆盖前一次?
  • @Brian 我修改了我的代码以在文件执行后删除文件。
  • 非常感谢你!你们太棒了,15 分钟后,我得到的信息比我真正要求的要多!我会尽我所能帮助别人。回到主题,我已经更新了我的原始帖子,使用 CreateProcess() 在我对系统的单次调用中是否有任何好处?
  • 第二个代码示例根本不起作用。参见CreateProcess()参数lpApplicationName的说明:在部分名称的情况下,该函数使用当前驱动器和当前目录来完成规范。该函数不会使用搜索路径。
【解决方案2】:

这是一种可以通过目录更改执行系统的方法:

// using AND_CMD like an operator to concat commands -- you can also just type it in one string: "edit & shutdown -h"...
// this works in c, too, but no dynamic variables are possible
//#define AND_CMD " & "

// c++
#define AND_CMD +" & "+

system(
    "cd c:\wamp64\bin\mysql\mysql5.7.14\bin" AND_CMD
    "PAUSE" AND_CMD
    "dir" AND_CMD
    "PAUSE" AND_CMD
    "mysql.exe -u root -p dataBase < tables.sql"
);

所以你只需要用字符串" &amp; " 加入命令。 如果您需要在程序本身的条件下运行代码/在下次调用system-函数时保留目录,您应该寻找替代方案或将命令通过管道传输到命令提示符中(例如,通过@987654324 运行您的程序@ 并通过输出例如printf 来调用命令。

【讨论】:

  • 或者只是为了保持舒尔:#define AND_CMD +string(" &amp; ")+
  • 我真的不明白那个宏的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 1970-01-01
  • 1970-01-01
  • 2014-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多