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

问题描述 投票:0回答:11

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

所以我正在考虑使用诸如

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

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

谢谢

c++ string http-redirect system call
11个回答
17
投票

共识似乎是不使用“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;
}

10
投票

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

尝试使用

popen

   #include <stdio.h>

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

   int pclose(FILE *stream);

但是,您可能不想这样做

ls
。 两个原因:

  • 如果你想获取目录列表,请直接使用文件系统API(
    readdir
    ),而不是使用shell命令并解析它。
  • 有人向我推荐了一篇 博客文章,最近解释了为什么解析
    ls
    输出是一个坏主意。

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;
}

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';
}

2
投票

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


1
投票

选项 4. 使用 popen();


0
投票

使用适当的 c 调用来读取目录中的文件,或者概括您的程序,以便它采用文件列表作为输入,并从 ls 将该列表通过管道传输到您的程序

> ls | yoursoftware

0
投票

我看到 3 个选项:

  1. 执行
    system("ls > tempfile")
    ,然后从临时文件中读取
    ls
    的输出
  2. 使用
    pipe()
    打开管道,然后使用
    fork()
    生成新进程。在子进程中关闭文件描述符 2 并通过调用
    dup()
    来替换它的写入管道末端。接下来,在子进程中调用
    exec("ls",...)
    。最后从父进程的管道中读取
    ls
    的输出
  3. 不要使用
    ls
    来枚举当前目录中的文件。您的程序中有一些函数可以正确执行此操作,即
    opendir(),readdir(),closedir

我强烈推荐选项3。


0
投票

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

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

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

同样,大多数响应都提供了使用本机 C 库获取目录内容的更好方法,但在某些情况下,诸如 pipeline()、fork()、dup()、exec()、system() 和popen() 适合与系统进程通信。


0
投票

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

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

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


0
投票

如果您不想创建太多代码,另一种方法是在 shell 命令中使用 > 将其转储到文件中。例如。 LS>

© www.soinside.com 2019 - 2024. All rights reserved.