最近在调试代码的时候,发现一个问题,在CentOS 服务器调试好好的代码,结果到了嵌入式上,居然出现异常了,因为有些命令在嵌入式设备上被裁掉了。如下面这段代码:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string>
#include <string.h>
#include <unistd.h>
bool executeSysCall(const char *cmd, std::string &out);
int main()
{
std::string command("file weChat.jpg");
std::string result;
if(executeSysCall(command.c_str(), result))
{
printf("exec result: %s\n", result.c_str());
}
return 0;
}
bool executeSysCall(const char *cmd, std::string &out)
{
if(cmd == nullptr)
{
return false;
}
FILE *fp = popen(cmd, "r");
if(fp == nullptr)
{
printf("error, popen: %s\n", strerror(errno));
return false;
}
char buf[1024] = {0};
out.clear();
while(fgets(buf, sizeof(buf), fp) != nullptr)
{
out.append(buf);
}
pclose(fp);
return true;
}
在 CentOS 执行结果是这样的:
可以看出,程序执行的结果和命令执行的结果是一样的。而当我重新编译程序,并且拷贝到嵌入式设备上执行时,结果是这样的:
第一行显示没有这个命令,第二执行结果是空的。为什么是这样呢?我以为命令不管执行成功和失败都能取到对应的结果,除非 popen() 返回的是NULL,但从执行结果来看,其返回值并非NULL。通过查看 man 手册知道,成功执行时,文件流会输出到标准输出,但似乎没提到错误的情况,那这个错误会不会输出到标准出错上了呢?我们看上面执行结果中的 ”sh: file: not found“ 是不是子进程输出的呢?如果是的话,那它应该也是输出到标准输出了啊,这里为什么拿不到结果呢?不解。。。
但又想到,如果popen()执行出错,信息被输出到标准出错的话,那我们是不是可以重定向,把标准出错重定向到标准输出呢?如果可以的话,我们是不是就可以拿到想要的结果了呢?修改代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string>
#include <string.h>
#include <unistd.h>
bool executeSysCall(const char *cmd, std::string &out);
int main()
{
std::string command("file weChat.jpg 2>&1");
std::string result;
if(executeSysCall(command.c_str(), result))
{
printf("exec result: %s\n", result.c_str());
}
sleep(10);
return 0;
}
bool executeSysCall(const char *cmd, std::string &out)
{
if(cmd == nullptr)
{
return false;
}
FILE *fp = popen(cmd, "r");
if(fp == nullptr)
{
printf("error, popen: %s\n", strerror(errno));
return false;
}
char buf[1024] = {0};
out.clear();
while(fgets(buf, sizeof(buf), fp) != nullptr)
{
out.append(buf);
}
pclose(fp);
return true;
}
加了重定向 2>&1,这样标准出错就被重定向到了标准输出上了。我们看一下执行结果:
结果已经取到了。