Debugger
Debugger

Reputation: 9488

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

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

Upvotes: 7

Views: 20214

Answers (11)

Utkarsh Majithia
Utkarsh Majithia

Reputation: 1

Another way to do it, if you don't want to create too much code is to use > in the shell command to dump it to a file. E.g. ls > ls.out

Upvotes: 0

CppNoob
CppNoob

Reputation: 2390

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

Upvotes: 0

RJB
RJB

Reputation: 366

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.

Upvotes: 0

SuperJames
SuperJames

Reputation: 777

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

Upvotes: 18

Steve
Steve

Reputation: 11

Option 4. Use popen();

Upvotes: 1

Douglas Leeder
Douglas Leeder

Reputation: 53310

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

Upvotes: 7

pajton
pajton

Reputation: 16226

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.

Upvotes: 0

Duck
Duck

Reputation: 27542

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

Upvotes: 4

Stephen
Stephen

Reputation: 49156

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.

Upvotes: 10

Harald Scheirich
Harald Scheirich

Reputation: 9764

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

Upvotes: 0

Dr. Watson
Dr. Watson

Reputation: 3820

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.

Upvotes: 2

Related Questions