C++执行命令行指令并获取命令行执行后的输出结果

1. popen(可获取命令行执行后的输出结果)

  • 概述

    • popen()可以执行shell命令,并读取此命令的返回值;  
      • popen()函数通过创建一个管道,调用fork()产生一个子进程,执行一个shell以运行命令来开启一个进程。可以通过这个管道执行标准输入输出操作。这个管道必须由pclose()函数关闭, 而不是fclose()函数(若使用fclose会产生僵尸进程)。pclose()函数关闭标准I/O流,等待命令执行结束,然后返回shell的终止状态。如果shell不能被执行,则pclose()返回的终止状态与shell已执行exit一样。
  • 函数原型

FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
  • type参数

    • 只能是读或者写中的一种,得到的返回值(标准I/O流)也具有和type相应的只读或只写类型。
    • 如果type是”r”则文件指针连接到command的标准输出
    • 如果type是”w”则文件指针连接到command的标准输入
  • command参数

    • 是一个指向以NULL结束的shell命令字符串的指针。这行命令将被传到bin/sh并使用-c标志,shell将执行这个命令。
  • 返回值

    • 如果调用fork()pipe()失败,或者不能分配内存将返回NULL,否则返回标准I/O流。
    • popen()没有为内存分配失败设置errno值
    • 如果调用fork()pipe()时出现错误,errno被设为相应的错误类型。
    • 如果type参数不合法,**errno将返回EINVA**L。

例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

void print_result(FILE *fp)
{
        char buf[100];

        if(!fp) 
        {
                return;
        }
        printf("\n>>>\n");
        while(memset(buf, 0, sizeof(buf)), fgets(buf, sizeof(buf) - 1, fp) != 0 ) {
                printf("%s", buf);
        }
        printf("\n<<<\n");
}

int main(void)
{
        FILE *fp = NULL;

        while(1) {
                fp = NULL;
                fp = popen("ls", "r");
                if(!fp) {
                        perror("popen");
                        exit(EXIT_FAILURE);
                }
                print_result(fp);
                pclose(fp);
                sleep(1);
        }
}

2. 使用Windows API的管道(可获取命令行执行后的输出结果,功能比2强大)

  • 使用匿名管道和CreateProcess函数实现不弹出黑框,获取命令行执行后输出结果
  • 使用CreateProcess可以设置命令行启动信息、 可以指定命令行执行的目录等等
std::wstring Connection::ExeCmd(std::wstring pszCmd)
{
    // 创建匿名管道
    SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
    HANDLE hRead, hWrite;
    if (!CreatePipe(&hRead, &hWrite, &sa, 0))
    {
        return TEXT(" ");
    }

    // 设置命令行进程启动信息(以隐藏方式启动命令并定位其输出到hWrite
    STARTUPINFO si = {sizeof(STARTUPINFO)};
    GetStartupInfo(&si);
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.wShowWindow = SW_HIDE;
    si.hStdError = hWrite;
    si.hStdOutput = hWrite;

    // 启动命令行
    PROCESS_INFORMATION pi;
    if (!CreateProcess(NULL, (LPWSTR)pszCmd.c_str(), NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
    {
        return TEXT("Cannot create process");
    }

    // 立即关闭hWrite
    CloseHandle(hWrite);

    // 读取命令行返回值
    std::string strRetTmp;
    char buff[1024] = {0};
    DWORD dwRead = 0;
    strRetTmp = buff;
    while (ReadFile(hRead, buff, 1024, &dwRead, NULL))
    {
        strRetTmp += buff;
    }
    CloseHandle(hRead);

    LPCSTR pszSrc = strRetTmp.c_str();
    int nLen = MultiByteToWideChar(CP_ACP, 0, buff, -1, NULL, 0);
    if (nLen == 0) 
        return std::wstring(L"");

    wchar_t* pwszDst = new wchar_t[nLen];
    if (!pwszDst) 
        return std::wstring(L"");

    MultiByteToWideChar(CP_ACP, 0, pszSrc, -1, pwszDst, nLen);
    std::wstring strRet(pwszDst);
    delete[] pwszDst;
    pwszDst = NULL;

    return strRet;
}

猜你喜欢

转载自blog.csdn.net/VonSdite/article/details/81295056