How to redirect the output of a system call to inside the program in C/C++?

こ雲淡風輕ζ 提交于 2019-12-03 14:52:48

问题


I'm writing a program in C++ which do some special treatment for all the files in the current directory on Linux OS.

So i was thinking of using system calls such as system("ls") to get the list of all files.

but how to store it then inside my program ? ( how to redirect the output of ls to let's say a string that i declared in the program )

Thanks


回答1:


I suggest you don't call out to ls - do the job properly, using opendir/readdir/closedir to directly read the directory.

Code example, print directory entries:

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



回答2:


The consensus seems to be not to use "ls". However, for anyone that is interested in a function to do this:

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



回答3:


I don't think you can use system to read the output.

Try using popen.

   #include <stdio.h>

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

   int pclose(FILE *stream);

But, you probably don't want to do this for ls. Two reasons:

  • If you want to get a directory listing use the file system api directly (readdir), instead of using shell commands and parsing it.
  • Someone pointed me to a blog post recently explaining why parsing ls output is a bad idea.



回答4:


A simple way to do this is to use the boost filesystem directory iterator. Or just use opendir/readdir/closedir as others have suggested. There is no real upside to the way you are headed.

Code example, print sizes for regular files in a specified directory:

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



回答5:


Are you on UNIX or Windows? On UNIX you would create a child process with the fork() call, and then create some pipes and assign the STDOUT of the child process to the STDIN of the parent process. On Windows there is bound to be something similar in the Win32 API.




回答6:


Option 4. Use popen();




回答7:


Either use the approiate c calls to read the files in the directory or you generalize your program so it takes a list of files as input and take that list from ls piped to your program

> ls | yoursoftware



回答8:


I see 3 options:

  1. Do system("ls > tempfile") and then read the output of ls from tempfile
  2. Open a pipe using pipe(), then use fork() to spawn a new process. In child process close file descriptor 2 and substitute writing end of pipe for it by calling dup(). Next, call exec("ls",...) in child process. Finally read the output of ls from the pipe in parent process
  3. Do not use ls for enumerating files in current directory. There are functions to do that right in your program, i.e. opendir(),readdir(),closedir.

I highly recommend option 3.




回答9:


I would think #2 from pajton is the most fitting answer to the question.

It may be "ls" is not the best example of a command for which you would want to use this since there are other native C library functions available to do this, but there are other programs that generate outputs that you may want to process immediately without having to perform a write/read to file.

#1 is also good on a UNIX/Linux type system that implements an efficient RAM file system that can be used for reading/writing system global data. On almost all systems it's a really good 'quick 'n' dirty' way to get the job done.

Again, most of the responses offer better ways of getting the contents of a directory using native C libraries, but there are instances where functions such as pipe(), fork(), dup(), exec(), system() and popen() are appropriate for communicating with system processes.




回答10:


Using the fork()/exec() and pipe() system calls seems to be the best general method on Unix. This allows easiest separation of the standard output and standard error streams of the invoked program. One can also wait on the spawned process and reap it, collecting its exit status. Finally one can use non-blocking I/O to read from the invoked program's output/error, if need be.

The biggest problem is that to achieve something similar on Windows, you'd possibly need to write several hundred lines of code. I didn't find a better way and haven't studied the problem in the Windows context.

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



来源:https://stackoverflow.com/questions/2655374/how-to-redirect-the-output-of-a-system-call-to-inside-the-program-in-c-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!