Cpp实现window上cmd执行效果
[TOC]
1.头文件包含部分
#include <iostream>
#include <string>
#include <cstdlib>
#include <windows.h> // 用于 Windows 系统的 SetCurrentDirectory 函数
#include <iostream>
:引入标准输入输出流库,这样就能使用std::cout
进行输出,std::cin
进行输入。#include <string>
:引入标准字符串库,用于处理std::string
类型的字符串。#include <cstdlib>
:引入标准库,包含了一些常用的函数和类型,这里可能在后续使用_popen
等函数时会依赖它。#include <windows.h>
:引入 Windows 系统的头文件,包含了许多 Windows API 函数,这里主要使用GetCurrentDirectoryA
和SetCurrentDirectoryA
函数。
2.main
函数部分
int main() {
std::string inputCommand;
char currentDir[MAX_PATH];
int main()
:程序的入口函数,返回值为int
类型,通常返回0
表示程序正常结束。std::string inputCommand;
:定义一个std::string
类型的变量inputCommand
,用于存储用户输入的命令。char currentDir[MAX_PATH];
:定义一个字符数组currentDir
,用于存储当前工作目录,MAX_PATH
是 Windows 系统中定义的最大路径长度。
3. 获取当前工作目录部分
// 使用 ANSI 版本的函数
if (!GetCurrentDirectoryA(MAX_PATH, currentDir)) {
std::cerr << "无法获取当前工作目录,错误代码: " << GetLastError() << std::endl;
return 1;
}
GetCurrentDirectoryA(MAX_PATH, currentDir)
:调用 Windows API 函数GetCurrentDirectoryA
获取当前工作目录,并将其存储到currentDir
数组中。A
表示使用 ANSI 版本,以处理char*
类型的字符串。if (!GetCurrentDirectoryA(MAX_PATH, currentDir))
:如果获取当前工作目录失败,GetCurrentDirectoryA
函数返回0
,则执行if
语句块。std::cerr << "无法获取当前工作目录,错误代码: " << GetLastError() << std::endl;
:使用std::cerr
输出错误信息,GetLastError()
函数返回最后一次系统调用的错误代码。return 1;
:返回非零值表示程序异常结束。
4.主循环部分
while (true) {
std::cout << currentDir << "> "; // 显示当前工作目录作为提示符
std::getline(std::cin, inputCommand);
while (true)
:创建一个无限循环,使程序持续等待用户输入命令。std::cout << currentDir << "> ";
:输出当前工作目录和一个大于号作为提示符,模拟命令行界面。std::getline(std::cin, inputCommand);
:从标准输入读取一行内容,并将其存储到inputCommand
变量中。
5.退出条件部分
if (inputCommand == "exit") {
break;
}
if (inputCommand == "exit")
:检查用户输入的命令是否为exit
。break;
:如果是exit
,则跳出循环,结束程序。
6.处理 cd
命令部分
// 处理 cd 命令
if (inputCommand.substr(0, 2) == "cd") {
std::string newDir = inputCommand.substr(3);
// 使用 ANSI 版本的函数
if (SetCurrentDirectoryA(newDir.c_str())) {
// 更新当前工作目录
if (!GetCurrentDirectoryA(MAX_PATH, currentDir)) {
std::cerr << "无法更新当前工作目录,错误代码: " << GetLastError() << std::endl;
continue;
}
}
else {
std::cerr << "无法更改目录到 " << newDir << std::endl;
}
continue;
}
if (inputCommand.substr(0, 2) == "cd")
:检查用户输入的命令是否以cd
开头。std::string newDir = inputCommand.substr(3);
:如果是以cd
开头,提取cd
后面的目录路径,存储到newDir
变量中。SetCurrentDirectoryA(newDir.c_str())
:调用 Windows API 函数SetCurrentDirectoryA
尝试将当前工作目录更改为newDir
。if (!GetCurrentDirectoryA(MAX_PATH, currentDir))
:如果更改成功,再次调用GetCurrentDirectoryA
函数更新currentDir
数组。如果更新失败,输出错误信息并继续下一次循环。else
:如果更改目录失败,输出错误信息并继续下一次循环。continue;
:跳过本次循环的剩余部分,继续等待用户输入下一个命令。
7.执行其他命令部分
// 使用 _popen 打开一个管道来执行命令
FILE* pipe = _popen(inputCommand.c_str(), "r");
if (!pipe) {
std::cerr << "无法打开管道!" << std::endl;
continue;
}
_popen(inputCommand.c_str(), "r")
:使用_popen
函数打开一个管道,执行用户输入的命令,并以只读模式读取命令的输出。if (!pipe)
:如果打开管道失败,输出错误信息并继续下一次循环。
8.读取命令输出部分
// 用于存储命令输出的缓冲区
char buffer[1024];
std::string res = "";
// 从管道中读取命令输出
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
res += buffer;
}
char buffer[1024];
:定义一个字符数组buffer
,用于存储从管道中读取的命令输出。std::string res = "";
:定义一个std::string
类型的变量res
,用于存储命令的完整输出。while (fgets(buffer, sizeof(buffer), pipe) != nullptr)
:使用fgets
函数从管道中读取数据,每次最多读取sizeof(buffer)
个字符,直到读取到文件末尾(返回nullptr
)。读取到的数据存储在buffer
中,并追加到res
变量中。
9.关闭管道并处理返回码部分
// 关闭管道
int returnCode = _pclose(pipe);
if (returnCode == 0) {
std::cout << "命令执行成功。" << std::endl;
std::cout << "命令输出信息如下:" << std::endl;
std::cout << res << std::endl;
}
else {
std::cout << "命令执行失败,返回码:" << returnCode << std::endl;
}
_pclose(pipe)
:关闭管道并返回命令的退出状态码。if (returnCode == 0)
:检查返回码是否为0
,0
通常表示命令执行成功,此时输出成功信息和命令的输出内容;否则输出失败信息和返回码。
10.源码
#include <iostream>
#include <string>
#include <cstdlib>
#include <windows.h> // 用于 Windows 系统的 SetCurrentDirectory 函数
int main() {
std::string inputCommand;
char currentDir[MAX_PATH];
// 使用 ANSI 版本的函数
if (!GetCurrentDirectoryA(MAX_PATH, currentDir)) {
std::cerr << "无法获取当前工作目录,错误代码: " << GetLastError() << std::endl;
return 1;
}
while (true) {
std::cout << currentDir << "> "; // 显示当前工作目录作为提示符
std::getline(std::cin, inputCommand);
if (inputCommand == "exit") {
break;
}
// 处理 cd 命令
if (inputCommand.substr(0, 2) == "cd") {
std::string newDir = inputCommand.substr(3);
// 使用 ANSI 版本的函数
if (SetCurrentDirectoryA(newDir.c_str())) {
// 更新当前工作目录
if (!GetCurrentDirectoryA(MAX_PATH, currentDir)) {
std::cerr << "无法更新当前工作目录,错误代码: " << GetLastError() << std::endl;
continue;
}
}
else {
std::cerr << "无法更改目录到 " << newDir << std::endl;
}
continue;
}
// 使用 _popen 打开一个管道来执行命令
FILE* pipe = _popen(inputCommand.c_str(), "r");
if (!pipe) {
std::cerr << "无法打开管道!" << std::endl;
continue;
}
// 用于存储命令输出的缓冲区
char buffer[1024];
std::string res = "";
// 从管道中读取命令输出
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
res += buffer;
}
// 关闭管道
int returnCode = _pclose(pipe);
if (returnCode == 0) {
std::cout << "命令执行成功。" << std::endl;
std::cout << "命令输出信息如下:" << std::endl;
std::cout << res << std::endl;
}
else {
std::cout << "命令执行失败,返回码:" << returnCode << std::endl;
}
}
return 0;
}