如何在C / C ++中将系统调用的输出重定向到程序内部?

时间:2010-04-16 18:41:54

标签: c++ string redirect system call

我正在用C ++编写一个程序,它对Linux OS上当前目录中的所有文件进行了一些特殊处理。

所以我考虑使用system("ls")之类的系统调用来获取所有文件的列表。

但是如何将它存储在我的程序中? (如何重定向ls的输出,让我们说一个我在程序中声明的字符串)

由于

10 个答案:

答案 0 :(得分:14)

共识似乎不是使用“ls”。但是,对于有兴趣执行此功能的任何人:

/**
 * Execute a command and get the result.
 *
 * @param   cmd - The system command to run.
 * @return  The string command line output of the command.
 */
string GetStdoutFromCommand(string cmd) {

    string data;
    FILE * stream;
    const int max_buffer = 256;
    char buffer[max_buffer];
    cmd.append(" 2>&1"); // Do we want STDERR?

    stream = popen(cmd.c_str(), "r");
    if (stream) {
        while (!feof(stream))
            if (fgets(buffer, max_buffer, stream) != NULL) data.append(buffer);
        pclose(stream);
    }
    return data;
}

答案 1 :(得分:10)

我认为您不能使用系统来读取输出。

尝试使用popen

   #include <stdio.h>

   FILE *popen(const char *command, const char *type);

   int pclose(FILE *stream);

但是,您可能不希望为ls执行此操作。有两个原因:

  • 如果要获取目录列表,请直接使用文件系统api(readdir),而不是使用shell命令并解析它。
  • 有人指着我blog post最近解释为什么解析ls输出是一个坏主意。

答案 2 :(得分:7)

我建议您不要呼叫ls - 正确完成工作,使用opendir/readdir/closedir直接读取目录。

代码示例,打印目录条目:

// $ gcc *.c && ./a.out 
#include <stdlib.h> // NULL
#include <stdio.h>  
#include <dirent.h>

int main(int argc, char* argv[]) {
  const char* path = argc <= 1 ? "." : argv[1];

  DIR* d = opendir(path);
  if (d == NULL) return EXIT_FAILURE;

  for(struct dirent *de = NULL; (de = readdir(d)) != NULL; )
    printf("%s/%s\n", path, de->d_name);

  closedir(d);
  return 0;
}

答案 3 :(得分:4)

一种简单的方法是使用boost filesystem目录迭代器。或者像其他人建议的那样使用opendir / readdir / closedir。你前进的方式没有真正的好处。

代码示例,指定目录中常规文件的打印大小:

// $ g++ listdir.cc -o listdir -lboost_filesystem && ./listdir
#include <iostream>
#include <boost/filesystem.hpp>

int main(int argc, char* argv[]) {
  using std::cout;
  using namespace boost::filesystem;

  std::string path(argc <= 1 ? "." : argv[1]);

  if (is_directory(path)) {
    for (directory_iterator itr(path); itr!=directory_iterator(); ++itr) {
      cout << itr->path().filename() << ' '; // display filename only
      if (is_regular_file(itr->status())) // display size for regular files
        cout << " [" << file_size(itr->path()) << ']';
      cout << '\n';
    }
  }
  else cout << (exists(path) ? "Found: " : "Not found: ") << path << '\n';
}

答案 4 :(得分:1)

选项4.使用popen();

答案 5 :(得分:0)

您是在UNIX还是Windows?在UNIX上,您将使用fork()调用创建子进程,然后创建一些管道并将子进程的STDOUT分配给父进程的STDIN。在Windows上,Win32 API中必然存在类似的东西。

答案 6 :(得分:0)

我看到3个选项:

  1. 执行system("ls > tempfile")然后从tempfile
  2. 读取ls的输出
  3. 使用pipe()打开管道,然后使用fork()生成新进程。在子进程中关闭文件描述符2并通过调用dup()替换管道的结尾。接下来,在子进程中调用exec("ls",...)。最后从父进程
  4. 中的管道中读取ls的输出
  5. 请勿使用ls枚举当前目录中的文件。在您的计划中有一些功能,即opendir(),readdir(),closedir
  6. 我强烈推荐选项3。

答案 7 :(得分:0)

使用适当的c调用来读取目录中的文件,或者对程序进行概括,以便将文件列表作为输入并将该列表从ls piped传递到程序

> ls | yoursoftware

答案 8 :(得分:0)

我认为pajton的#2是这个问题最合适的答案。

可能“ls”不是您想要使用它的命令的最佳示例,因为可以使用其他本机C库函数来执行此操作,但是还有其他程序可以生成您可能需要的输出无需执行写入/读取文件即可立即处理。

#1在UNIX / Linux类型系统上也很好,它实现了一个高效的RAM文件系统,可用于读/写系统全局数据。几乎在所有系统上,它都是一种非常好的“快速”“脏”方式来完成工作。

同样,大多数响应提供了使用本机C库获取目录内容的更好方法,但是有些实例包括pipe(),fork(),dup(),exec(),system( )和popen()适合与系统进程通信。

答案 9 :(得分:0)

使用fork()/ exec()和pipe()系统调用似乎是Unix上最好的通用方法。这样可以最简单地分离调用程序的标准输出和标准错误流。人们也可以等待产生的过程并收获它,收集它的退出状态。最后,如果需要,可以使用非阻塞I / O从调用的程序的输出/错误中读取。

最大的问题是,要在Windows上实现类似的功能,您可能需要编写几百行代码。我没有找到更好的方法,并且没有在Windows环境中研究过这个问题。

http://support.microsoft.com/kb/190351