92

I've got a utility that outputs a list of files required by a game. How can I run that utility within a C program and grab its output so I can act on it within the same program?

UPDATE: Good call on the lack of information. The utility spits out a series of strings, and this is supposed to be portable across Mac/Windows/Linux. Please note, I'm looking for a programmatic way to execute the utility and retain its output (which goes to stdout).

asked Sep 4, 2008 at 3:01
6
  • see also stackoverflow.com/questions/125828/… Commented Sep 25, 2012 at 22:30
  • If you want stderr as well you can redirect, for example call ls nonexistant-name 2>&1 Commented Apr 10, 2013 at 3:11
  • 10
    This is not a duplicate; the linked question is C++ specific, while this question is about C. Commented Mar 22, 2016 at 22:21
  • 4
    I'm voting to reopen this question as it not a duplicate, it's about C not C++ Commented Jun 20, 2017 at 9:51
  • see also stackoverflow.com/questions/9405985/… Commented Sep 3, 2017 at 15:37

9 Answers 9

91

As others have pointed out, popen() is the most standard way. And since no answer provided an example using this method, here it goes:

#include <stdio.h>
#define BUFSIZE 128
int parse_output(void) {
 char *cmd = "ls -l"; 
 
 char buf[BUFSIZE] = {0};
 FILE *fp;
 if ((fp = popen(cmd, "r")) == NULL) {
 printf("Error opening pipe!\n");
 return -1;
 }
 while (fgets(buf, BUFSIZE, fp) != NULL) {
 // Do whatever you want here...
 printf("OUTPUT: %s", buf);
 }
 if (pclose(fp)) {
 printf("Command not found or exited with error status\n");
 return -1;
 }
 return 0;
}

Sample output:

OUTPUT: total 16
OUTPUT: -rwxr-xr-x 1 14077 14077 8832 Oct 19 04:32 a.out
OUTPUT: -rw-r--r-- 1 14077 14077 1549 Oct 19 04:32 main.c
answered Mar 10, 2015 at 18:42
Sign up to request clarification or add additional context in comments.

9 Comments

Shouldn't if(pclose(fp)) be if(pclose(fp) == -1)?
@CoolGuy: depends on what you want. pclose() return -1 if there was an error obtaining the command's exit status, otherwise it returns the exit status itself. As commands traditionally set exit status 0 to indicate success, by checking if(pclose(fp)) we're testing for errors in either pclose() or the command.
Thank you so much for this example, it pipes the output of another program to the output of the current program. Thank you!
@GabrielStaples: fgets() is more suitable when reading text output rather than binary, as it automatically fetches one line at a time, splitting on newlines. Both require the while loop, as you cannot be sure the whole output will fit in BUFSIZE.
The traditional way is to use {0} in C. IIRC, gcc has supported the C++ style {} even in C code for a long time.
|
61

For simple problems in Unix-ish environments try popen().

From the man page:

The popen() function opens a process by creating a pipe, forking and invoking the shell.

If you use the read mode this is exactly what you asked for. I don't know if it is implemented in Windows.

For more complicated problems you want to look up inter-process communication.

answered Sep 4, 2008 at 3:04

4 Comments

some examples of how to properly use popen() would be nice.
I've added a link to the Open Group man page for the function, which includes an example. Basically popen geves you a file pointer very much like fopen. It's just that it lets you write to the standard input or read from the standard output of a program instead of interacting with a disk file. That's unix's "everything is a file" philosophy at work. Some implementations extend the standard by allowing bi-directional communication.
Thi s answer indicates that popen is available on Windows.
For the solution using the raw file handles (if you need asynch I/O for example), see stackoverflow.com/questions/9405985/…
11

popen is supported on Windows, see here:

http://msdn.microsoft.com/en-us/library/96ayss4b.aspx

If you want it to be cross-platform, popen is the way to go.

answered Sep 10, 2008 at 3:28

Comments

8

Well, assuming you're on a command line in a windows environment, you can use pipes or command line redirects. For instance,

commandThatOutputs.exe > someFileToStoreResults.txt

or

commandThatOutputs.exe | yourProgramToProcessInput.exe

Within your program, you could use the C standard input functions to read the other programs output (scanf, etc.): http://irc.essex.ac.uk/www.iota-six.co.uk/c/c1_standard_input_and_output.asp . You could also use the file example and use fscanf. This should also work in Unix/Linux.

This is a very generic question, you may want to include more details, like what type of output it is (just text, or a binary file?) and how you want to process it.

Edit: Hooray clarification!

Redirecting STDOUT looks to be troublesome, I've had to do it in .NET, and it gave me all sorts of headaches. It looks like the proper C way is to spawn a child process, get a file pointer, and all of a sudden my head hurts.

So heres a hack that uses temporary files. It's simple, but it should work. This will work well if speed isn't an issue (hitting the disk is slow), or if it's throw-away. If you're building an enterprise program, looking into the STDOUT redirection is probably best, using what other people recommended.

#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
 FILE * fptr; // file holder
 char c; // char buffer
 system("dir >> temp.txt"); // call dir and put it's contents in a temp using redirects.
 fptr = fopen("temp.txt", "r"); // open said file for reading.
 // oh, and check for fptr being NULL.
 while(1){
 c = fgetc(fptr);
 if(c!= EOF)
 printf("%c", c); // do what you need to.
 else
 break; // exit when you hit the end of the file.
 }
 fclose(fptr); // don't call this is fptr is NULL. 
 remove("temp.txt"); // clean up
 getchar(); // stop so I can see if it worked.
}

Make sure to check your file permissions: right now this will simply throw the file in the same directory as an exe. You might want to look into using /tmp in nix, or C:\Users\username\Local Settings\Temp in Vista, or C:\Documents and Settings\username\Local Settings\Temp in 2K/XP. I think the /tmp will work in OSX, but I've never used one.

answered Sep 4, 2008 at 3:05

1 Comment

c should be an int because fgetc returns an int, not a char.
3

In Linux and OS X, popen() really is your best bet, as dmckee pointed out, since both OSs support that call. In Windows, this should help: http://msdn.microsoft.com/en-us/library/ms682499.aspx

answered Sep 4, 2008 at 3:22

Comments

2

MSDN documentation says If used in a Windows program, the _popen function returns an invalid file pointer that causes the program to stop responding indefinitely. _popen works properly in a console application. To create a Windows application that redirects input and output, see Creating a Child Process with Redirected Input and Output in the Windows SDK.

answered May 12, 2010 at 22:27

Comments

1

You can use system() as in:

system("ls song > song.txt");

where ls is the command name for listing the contents of the folder song and song is a folder in the current directory. Resulting file song.txt will be created in the current directory.

JB.
42.5k13 gold badges83 silver badges109 bronze badges
answered Nov 11, 2013 at 13:17

2 Comments

what if I wanna redirect other programs output into a file ? not an os command
No, this is a very bad way to do it. Do it properly using pipes, don't be leaving temporary files all over the filesystem.
0

While the accepted answer suggested popen, it is worth mentioning that popen on windows might have unwanted side effects, especially for GUI applications.

If used in a Windows program, the _popen function returns an invalid file pointer that causes the program to stop responding indefinitely. _popen works properly in a console application.

I was surprised that there isn't a lightweight library that does that cross-platform. So I decided to create a library since I need the functionality anyway.

Here's the library https://github.com/Neko-Box-Coder/System2

It works for posix and windows systems. (It doesn't use popen for windows so it should also work in GUI applications)

It can send input and receive output from command.

And have blocking and non-blocking version.

And it has both header only and source version as well

answered Feb 25, 2024 at 19:29

Comments

-3
//execute external process and read exactly binary or text output
//can read image from Zip file for example
string run(const char* cmd){
 FILE* pipe = popen(cmd, "r");
 if (!pipe) return "ERROR";
 char buffer[262144];
 string data;
 string result;
 int dist=0;
 int size;
 //TIME_START
 while(!feof(pipe)) {
 size=(int)fread(buffer,1,262144, pipe); //cout<<buffer<<" size="<<size<<endl;
 data.resize(data.size()+size);
 memcpy(&data[dist],buffer,size);
 dist+=size;
 }
 //TIME_PRINT_
 pclose(pipe);
 return data;
}
answered Jul 15, 2013 at 10:11

2 Comments

What language is it? Surely not C (string.resize?)
looks like c++ :(

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.