[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Redirecting cout in a C++ program to a string.

Posted on 2009-04-18
16
Medium Priority
?
527 Views
Last Modified: 2012-05-06
I need to execute the Linux "system" call -- for example, system(" ls -al " ); but I don't want the output from it to go to the terminal. I need to capture that output in a string. It seems that cout.rdbuf could be used to do this, but I can't get it to work. popen has been suggested, but I feel like I'm throwing in the towel if cout could just be redirected for the system call and then returned to normal.

Is there a program I could test that would do this simple "ls -al" with cout redirection? Is it possibly that system uses cerr instead and I'm going to the wrong place?
0
Comment
Question by:Zzoni
  • 9
  • 7
16 Comments
 
LVL 53

Expert Comment

by:Infinity08
ID: 24175371
You could get it to work with rdbuf, and a lot of process magic. But I'd rather just use popen to create a pipe from the called application to the calling process, so you can read the output of the program from that pipe :

        http://linux.die.net/man/3/popen

It is one of the most commonly used approaches for your problem.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24175387
So, for your example, that would be something like :
char line[256] = { 0 };
 
FILE *procout = popen("ls -al", "r");
if (!procout) {
  /* oops : failed opening the stream */
  exit(1);
}
 
while (fgets(procout, line, 256)) {
  /* do something with the line ... */
}
 
pclose(procout);

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24175393
The fgets call was obviously wrong in my previous post, and should have been fgets(line, 256, procout) instead heh ;)
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 

Author Comment

by:Zzoni
ID: 24175396
I guess I understand your sentiment. But I don't see why there is a lot of process magic involved. The suggestions I've found using google suggest a cout.rdbuf redirection to a string -- it seems straight forward.  But I don't have an example that works. It doesn't crash, but the strings are always empty after the system call.

I will go your way in the end. But I'm not going to give up until I find a good reason that C++ doesn't have the ability already.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24175418
>> But I'm not going to give up until I find a good reason that C++ doesn't have the ability already.

That good reason is that C++ is not really aware of other processes (let alone other threads), so you need to make use of platform specific behavior to interact with other processes. popen is a function that was specifically designed for the purpose of getting access to the standard input or output of another process, so you might as well use it if that's what you need to do ;)

If you're not convinced, then consider that popen might not be part of the C++ standard, but it is pretty standard, and supported by a wide range of platforms (at least those that are POSIX compliant).

Btw, note that the rdbuf is used within a process, not between two different processes.
0
 
LVL 53

Accepted Solution

by:
Infinity08 earned 375 total points
ID: 24175422
>> (at least those that are POSIX compliant).

And many more that are partially compliant.
0
 

Author Comment

by:Zzoni
ID: 24175462
Yes, you make a good point, and you also included a useful example. Thanks. I expanded it to do what I need. I'll attach it.

Thanks!
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
 
int main() {
  char line[256] = { 0 };
 
  FILE *procout = popen("ls -al", "r");
  if(!procout) {
    /* oops : failed opening the stream */
    exit(1);
  }
 
  vector<string> captured_vec;
  while( fgets(line, 256, procout) ) {
    captured_vec.push_back( line );
  }
  for( vector<string>::iterator iter = captured_vec.begin();
       iter != captured_vec.end();
       ++iter ) {
    cout << *iter;
  }
 
  pclose(procout);
}

Open in new window

0
 

Author Closing Comment

by:Zzoni
ID: 31571790
This is not *exactly* what I was looking for, but it works and I can move on!
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24175494
>> This is not *exactly* what I was looking for

Then maybe I misunderstood what you were trying to do ?

If the idea is to get access to the standard output of a called process, then popen is your best bet, and I'd argue that that IS exactly what you wanted.

If it was something else you needed, maybe I can be of further assistance ?

Note that it is generally recommended to give the experts a chance to earn an A grade, rather than just closing it with a B grade (which signifies that the answer was incomplete and/or inaccurate). A B grade is used for those cases where the expert comments helped, but weren't sufficient in answering the question - ie. the asker had to do some extra work to get it to work or make it a workable solution.
0
 

Author Comment

by:Zzoni
ID: 24175790
Well, I'm new to the expert exchange, and I didn't realize that a B implied not fully answering the question.
It's really no big deal to me whether I state A or B. Is there a way to "update" my response?

You were very helpful and your example got me right on to a solution that fits my needs so I'm willing to do whatever you'd like.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24175929
The important thing is that you get your answer. So, if you're happy with it, then that's fine with me :) If not, then please don't hesitate to continue asking questions about this in this thread.

For future reference, this FAQ entry might be interesting :

        http://www.experts-exchange.com/help.jsp?hi=403
0
 

Author Comment

by:Zzoni
ID: 24176011
Great. You've been very helpful. In fact, I think you've uncovered why my previous code that was redirectlng cout to a string did not work: system(..) apparently does NOT use the cout stream. Now it all makes sense in fact. Why should it?! Silly assumption on my part.

I've attached a program that shows my problem. It redirects cout, but apparently not system(..) output. Right after the system call, I do a cout to test it, and it does show up in the "captured" string.

So, unless you know a way to get system(..) to send its output to cout, your popen solution seems to be the best yet.
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
 
class outbuf : public std::streambuf {
public:
  outbuf() {
    // no buffering, overflow on every char
    setp(0, 0);
  }
 
  virtual int_type overflow(int_type c = traits_type::eof()) {
    // add the char to wherever you want it, for example:
    // DebugConsole.setText(DebugControl.text() + c);
    captured.push_back( c );
    return c;
  }
  string get_captured() {
    return captured;
  }
private: 
  string captured;
};
 
int main() {
  // set std::cout to use my custom streambuf
  outbuf ob;
  std::streambuf *sb = std::cout.rdbuf(&ob);
 
  system( "ls -al" );
  cout << "this is a test not called from system" << endl;
    
  // make sure to restore the original so we don't get a crash on close!
  std::cout.rdbuf(sb);
 
  cerr << "\n\nCaptured text:" << ob.get_captured() << endl;
  return 0;
}

Open in new window

0
 

Author Comment

by:Zzoni
ID: 24176020
I should credit Dustin Getz, Éric Malenfant, and Evan Teran for their Stackoverflow posts regarding this problem/solution.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24176025
>> system(..) apparently does NOT use the cout stream.

It's slightly more complicated than that. system() basically creates a new process to run the specified command. That process will use stdout and stdin just like any other process, except that you won't see it from the calling process, since it goes directly to the shell (ie. the output doesn't pass through your process). That's why you can't see the output of the command on your process's standard output.

That's the reason I was talking about process magic earlier, because you have to trick the called procss into forwarding its standard output to your process's standard output without using pipes. It's a lot easier to just use a pipe (and use popen to do that).
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24176030
Ok, I'll be offline for a while now, but don't hesitate to ask further questions about this, and I will get to them as soon as I get back online.
0
 

Author Comment

by:Zzoni
ID: 24176173
Yes, exactly. I'm kicking myself for not realizing that it's unlikely at best to expect the running program to receive a "system" call's output.

Thanks for all the help.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and inf…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to use strings and some functions related to them in the C programming language.
Suggested Courses

873 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question