LinuxQuestions.org
View the Most Wanted LQ Wiki articles.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
LinkBack Search this Thread
Old 11-14-2009, 03:04 PM   #1
Kunsheng
Member
 
Registered: Mar 2009
Posts: 82

Rep: Reputation: 16
Running external program using C and read the result output


I am running some external executable inside C and getting the output from the executable using pipe like below:

1. create pipe

2. fork a child process to execute the program

3. parent reads from pipe


I know in Perl there is something pretty easy like:

my $result = qx (command);

Scalar $result will contain all std output from the command, just wondering if C has the same thing ? A pipe reads is working but seems too much work ?
 
Old 11-14-2009, 03:38 PM   #2
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: Slackware64 13.37, Kubuntu 10.04
Posts: 2,831

Rep: Reputation: Disabled
Before anyone suggests it, don't use popen. You'll need to fork at the very least so that you can replace standard out for the command to be executed. Look at the manpages for pipe, dup2, fork, system, and execv. I haven't told you how to set it up because I'm not quite sure the context; e.g. is it a one-time thing, do you need continued communication with the command, does your program need to do something else in the meantime, does your program need to wait until the other command finishes, does your program need to kill the command when it exits, does the command need terminal access, is it merely a command name and arguments or does it have shell operators, does it need to run under the same user or a different one? I'm sure I've forgotten something.
Kevin Barry
 
Old 11-15-2009, 03:05 PM   #3
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: ubuntu
Posts: 2,523

Rep: Reputation: 92
Quote:
Originally Posted by ta0kira View Post
Before anyone suggests it, don't use popen.
Why's that?
It would be the easiest way to do it, and would be closest to the perl example the OP mentioned.

Last edited by Hko; 11-15-2009 at 03:09 PM. Reason: fixed typo
 
Old 11-15-2009, 04:41 PM   #4
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: washington U.S.
Distribution: Damn Small Linux, KateOs, M$ Ickdows Vista, My own OS
Posts: 2,094

Rep: Reputation: 104Reputation: 104
what about
Code:
#include <stdlib.h>
#include <stdio.h>
int main(){
char c;
system("whoami > $temp$.###");
FILE *f = fopen("$temp$.###", "r");
while(!feof(f)){c = fgetc(f); printf("%c", c);}
fclose(f);
remove ("$temp%.###");
}
 
Old 11-15-2009, 04:44 PM   #5
Kunsheng
Member
 
Registered: Mar 2009
Posts: 82

Original Poster
Rep: Reputation: 16
I got confused about that too... was pipe a mostly used way (if not only) for that ? I guess it might also be the low-level behaviors behind that perl 'qw' command ?

Quote:
Originally Posted by Hko View Post
Why's that?
It would be the easiest way to do it, and would be closest to the perl example the OP mentioned.
 
Old 11-15-2009, 05:02 PM   #6
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: Slackware64 13.37, Kubuntu 10.04
Posts: 2,831

Rep: Reputation: Disabled
Quote:
Originally Posted by Hko View Post
Why's that?
It would be the easiest way to do it, and would be closest to the perl example the OP mentioned.
I'm not dead-set against it, but you don't have control over the process when you use it (especially the pipe direction you didn't choose,) and I've seen implementations that didn't account for already having a lot of files open.
Kevin Barry
 
Old 11-15-2009, 05:06 PM   #7
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: Slackware64 13.37, Kubuntu 10.04
Posts: 2,831

Rep: Reputation: Disabled
Quote:
Originally Posted by Kunsheng View Post
I got confused about that too... was pipe a mostly used way (if not only) for that ? I guess it might also be the low-level behaviors behind that perl 'qw' command ?
pipe is usually used to create a descriptor pair before forking. After forking, dup2 is often used to replace standard input or output with the pipe, followed by system or execv, allowing the parent to communicate with the child using its standard input and output.
Kevin Barry
 
Old 11-15-2009, 06:40 PM   #8
SaintDanBert
Member
 
Registered: Jan 2009
Location: Austin, TX
Distribution: Mint-11, v11.04 Ubuntu & Kubuntu
Posts: 853
Blog Entries: 3

Rep: Reputation: 48
Quote:
Originally Posted by smeezekitty View Post
what about
Code:
#include <stdlib.h>
#include <stdio.h>
int main(){
char c;
system("whoami > $temp$.###");
FILE *f = fopen("$temp$.###", "r");
while(!feof(f)){c = fgetc(f); printf("%c", c);}
fclose(f);
remove ("$temp%.###");
}
The system( ) function does not return until there is an exit from the
command string. This is why folks have mentioned fork() and execv() --
both of which will return to the caller before the command exits.

Also, Just because the command passed to system(...) does a write does not mean that a file is visible to the subsequent fopen(...). As I recall, you need open+write+close before a following fopen will see a file that exists. An alternative requires that there is enough written to force a buffer flush, or an explicit call to flush() or similar in the code.

It has been a long time since I coded at this detail level, so I'm sure there are things forgotten. I hope these comments give you helpful things to think about.

~~~ 0;-Dan
 
Old 11-15-2009, 08:22 PM   #9
paulsm4
Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,849
Blog Entries: 1

Rep: Reputation: Disabled
Hi, Kunsheng -

The called "popen()/fgets ()/pclose()" are probably the ideal solution to your problem.

No tool is right for every job - but I'm frankly not aware of any issues or problems of any kind with "popen()". Certainly none that you wouldn't ALSO face if you did the "fork()/exec()/pipe()/etc" all yourself.

IMHO .. PSM
 
Old 11-16-2009, 01:26 PM   #10
Kunsheng
Member
 
Registered: Mar 2009
Posts: 82

Original Poster
Rep: Reputation: 16
Thanks, folks. I checked that a little bit, popen is invoking a new shell to run the command, which is beaten by fork+pipe functions in performance.

It is something similar to difference between system() and exec family.
 
Old 11-16-2009, 02:17 PM   #11
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: FreeBSD, Puppy
Posts: 3,016

Rep: Reputation: 91
funnily enough I've been playing with this today,
a function helper that runs like execlp(3)
after which you can read the output from stdin.
(not tidied up yet)


Code:
#include <stdarg.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <pthread.h>


pid_t helper(char * prog, ...) {

    char * args[ARG_MAX];
    int n = 0;
    va_list ap;
    char * p = prog;
    int filedes[2];
    pid_t pid;


    args[n++] = (char *) prog;
    va_start(ap, prog);
    while (p) {

	p = va_arg(ap, char *);
	args[n++] = p;
	//printf("got:%s\n", p);
    }
    va_end(ap);

    /* args done */

    if (-1 == pipe(filedes)) {
	perror("pipe failed");
	return 0;
    }

    switch (pid = fork()) {

    case -1:
	perror("fork failed");
	pid = 0;
	break;

    case 0:   /* child */
	close(1);
	dup(filedes[1]);
	close(filedes[1]);
	execvp(prog, args);
	perror(prog);
	break;

    default: /* parent */
	close(0);
	dup(filedes[0]);
	close(filedes[0]);
	close(filedes[1]);
	break;
	

    }

    return pid;


}




#define SZ 4096
int main (int argc, char ** argv) {


    char  buffer[SZ];
    pid_t pid;
    pthread_t thr[1];


    pid = helper ("cksum", "1", "2", "3", (char *) 0 );
    printf("started %d\n", pid);
    while(fgets(buffer, SZ, stdin) ) {

	printf(":%s", buffer);
    }


   return 0;
}
 
Old 11-16-2009, 07:23 PM   #12
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: washington U.S.
Distribution: Damn Small Linux, KateOs, M$ Ickdows Vista, My own OS
Posts: 2,094

Rep: Reputation: 104Reputation: 104
Quote:
Originally Posted by SaintDanBert View Post
The system( ) function does not return until there is an exit from the
command string. This is why folks have mentioned fork() and execv() --
both of which will return to the caller before the command exits.

Also, Just because the command passed to system(...) does a write does not mean that a file is visible to the subsequent fopen(...). As I recall, you need open+write+close before a following fopen will see a file that exists. An alternative requires that there is enough written to force a buffer flush, or an explicit call to flush() or similar in the code.

It has been a long time since I coded at this detail level, so I'm sure there are things forgotten. I hope these comments give you helpful things to think about.

~~~ 0;-Dan
But maybe its better to wait for the child to finish before your read the output?
 
Old 11-17-2009, 11:08 AM   #13
theNbomr
Senior Member
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 4,320

Rep: Reputation: 539Reputation: 539Reputation: 539Reputation: 539Reputation: 539Reputation: 539
Quote:
Originally Posted by smeezekitty View Post
But maybe its better to wait for the child to finish before your read the output?
Better depends on the context. It sounds like the OP wants his parent process to interact with the child. That is the whole point of having popen(). The downside of popen() versus pipe()+fork()+exec() is that popen() launches a shell, which may be useless.
A couple of websites provide useful samples and tutorials for contrast:

UNIX System Calls and Subroutines using C
Beej's Guide to UNIX IPC

--- rod.
 
Old 11-17-2009, 12:03 PM   #14
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: Slackware64 13.37, Kubuntu 10.04
Posts: 2,831

Rep: Reputation: Disabled
Quote:
Originally Posted by smeezekitty View Post
But maybe its better to wait for the child to finish before your read the output?
If too much output is sent without reading, the next write will block. That might make the processes deadlock waiting for each other.
Kevin Barry
 
Old 11-17-2009, 12:13 PM   #15
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 1,985

Rep: Reputation: 102Reputation: 102
Also pipes are a lot faster than possibly touching the disk, and you don't have an annoying race condition to deal with.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Strange output when running a C program over itself Dralnu Programming 5 05-13-2009 05:15 PM
How do you read gzip output from 'C' program? bjdea1 Programming 2 03-12-2006 06:24 PM
Capturing standard output from external program brianvdc Linux - Software 1 02-12-2003 04:20 AM


All times are GMT -5. The time now is 09:20 AM.

Main Menu
 
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: @linuxquestions
Open Source Consulting | Domain Registration