C: Run a System Command and Get Output? [duplicate] - c

This question already has answers here:
How can I run an external program from C and parse its output?
(8 answers)
Closed last month.
I want to run a command in linux and get the text returned of what it outputs, but I do not want this text printed to screen. Is there a more elegant way than making a temporary file?

You want the "popen" function. Here's an example of running the command "ls /etc" and outputing to the console.
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
FILE *fp;
char path[1035];
/* Open the command for reading. */
fp = popen("/bin/ls /etc/", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit(1);
}
/* Read the output a line at a time - output it. */
while (fgets(path, sizeof(path), fp) != NULL) {
printf("%s", path);
}
/* close */
pclose(fp);
return 0;
}

You need some sort of Inter Process Communication. Use a pipe or a shared buffer.

Related

Redirecting stdin and stdout?

So im trying to redirect the I/O to read command from file then when user runs the output command it will print the compiled command to output file.
For example on the terminal:
./run 2 < test.txt // This would take file using dup and take the input
Then when you want to output the compile:
./run 1 > output.txt // and it would put into an output file
So far i know how to output to a file but my problem is with the input. how do i get the command from the file using the dup2() function? I tried researching this but no luck.
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
char inputForOutput[100];
void functionOutput(int argc, char **argv){
int ofd; //Init of file desc.
ofd = open(argv[1], O_CREAT|O_TRUNC|O_WRONLY);
dup2(ofd, 1);//Duplicates to stdout
system("ls");//Copies commnd given to output_file
}
//Function is called when argument number is == 1
void functionInput(int argc, char **argv){
FILE *ifd;
printf("\n %s \n ", argv[2]);
ifd = fopen(argv[2] , "r");
if (ifd == NULL){
perror("No file found");
exit(1);
}
fscanf(ifd,"%s",inputForOutput);
printf("\n**%s**\n",inputForOutput);
}
int main(int argc, char **argv)
{
int output;
int input;
output = strcmp("1", argv[1]);
input = strcmp("2" ,argv[1]);
if (output == 0 ) { //Fail safe for number of arguments
functionOutput(argc, argv);
}
else if ( input == 0){
functionInput(argc, argv);
}
else{
fprintf(stderr, "How to use: %s function output_file\n", argv[0]); // FAIL SAFE IF INPUT DOES NOT MATCH BOTH FUNCTIONS
}
return 0;
}
To redirect input and output, use this format
myprogram > out.txt < in.txt //read from in.txt, write to out.txt
myprogram < in.txt > out.txt //read from in.txt, write to out.txt
myprogram < in.txt //redirect stdin only
myprogram > out.txt //redirect stdout only
myprogram //no redirection
...
This should work with any program. Example:
int main(void)
{
char buf[1000];
if(fgets(buf, sizeof(buf), stdin))
printf("write: %s\n", buf);
return 0;
}
To redirect stdin/stdout in the program, use the standard method
freopen("output.txt", "w", stdout);
printf("Testing...");
fclose(stdout);
freopen("input.txt", "r", stdin);
char buf[100];
fgets(buf, sizeof(buf), stdin);
fclose(stdin);
Alternatively, set FILE *fin = stdin; FILE* fout = stdout; to redirect the opposite way.
Next, to write a program using argv elements, always test argc first. The code below shows an example.
#include <stdio.h>
#include <string.h>
int redirect(int argc, char **argv, int *index)
{
//no more redirection!
if(*index >= argc)
return 1;
//not enough parameters
if(*index + 1 >= argc)
{
printf("wrong usage\n");
return 0;
}
if(strcmp(argv[*index], "<") == 0)
{
*index++; //next parameter is to redirect input
if(!freopen(argv[*index], "r", stdin))
printf("error, redirect input failed");
}
else if(strcmp(argv[*index], ">") == 0)
{
*index++; //next parameter is to redirect output
if(!freopen(argv[*index], "w", stdout))
printf("error, redirect output failed");
}
else
{
printf("wrong usage\n");
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
int index = 1;
if(!redirect(argc, argv, &index))
return 1;
if(!redirect(argc, argv, &index))
return 1;
//read
char buf[1000];
if(fgets(buf, sizeof(buf), stdin))
{
//write
printf("write: %s\n", buf);
}
fclose(stdin);
fclose(stdout);
return 0;
}
With functionOutput() you have a good first attempt at capturing the output of a system command to a file. Actually, that is the function called when the first argument is 1, so you might want to update your comment. Also, you're creating a file with the name stored in argv[1], which we already know is 1 so it's probably not doing what you expect, and you probably want:
ofd = open(argv[2], O_CREAT|O_TRUNC|O_WRONLY);
With functionInput() you're reading the first non-whitespace entry from the file. If you're telling it to read the file which you output using the functionOutput() function, that is likely to be (some of) the name of the first file which was listed by ls.
I'm finding it unclear what you're wanting to do which isn't that. If you want to find out what the command was which you ran to generate the output, that information is not available from the file itself, because you didn't write it there. If that's what you want, you may want to consider writing the command as the first line of the file, followed by the output. Then when you read it, you can assume that the first line is the command run, followed by the output of that command.
If I understand your question, and you want to run your program in essentially two different modes, (1) you want to take input if there is input to be taken on stdin; and (2) if there is no input waiting, you want to do an output, then select/pselect or poll are what you are looking for.
For example select allows you to check whether there is input ready to be read on a file descriptor (or set of descriptors) and it will return the number of descriptors with input waiting (or -1 and set errno on error). You could simply use the STDIN_FILENO (a/k/a fd 0) to check if there is input on stdin, e.g.
#include <stdio.h>
#include <unistd.h> /* for STDIN_FILENO */
#include <sys/select.h> /* for pselect */
int input (int filedes)
{
fd_set set;
/* declare/initialize zero timeout */
struct timespec timeout = { .tv_sec = 0 };
/* Initialize the file descriptor set. */
FD_ZERO (&set);
FD_SET (filedes, &set);
/* check whether input is ready on filedes */
return pselect (filedes + 1, &set, NULL, NULL, &timeout, NULL);
}
int main (void)
{
if (input (STDIN_FILENO))
puts ("doing input routine");
else
puts ("doing output routine");
return 0;
}
(note: from the man page "select() uses a timeout that is a struct timeval (with seconds and microseconds), while pselect() uses a struct timespec (with seconds and nanoseconds).")
Example Use/Output
$ ./bin/select_peekstdin < file
doing input routine
$ ./bin/select_peekstdin
doing output routine

Debugging C program with two arguments passed

I have fixed some syntactical errors in my code and now the program compiles fine. But when I execute the program the outputFile is empty. outputFile should have contents of inputFile in reverse order. I am trying to debug code in CodeLite IDE.
I need to debug the code with two arguments passed (inputFile and outputFile). I don't seem to find that option in CodeLite IDE. How do I do that ?
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFFER_SIZE 256
int main (int argc, char *argv[]){
FILE *inputFile, *outputFile;
int fileSize;
int pointer;
char buffer[BUFFER_SIZE];
/* Check for correct user's inputs. */
if( argc !=3 ) {
fprintf(stderr, "USAGE: %s inputFile outputFile.\n", argv[0]);
exit(-1);
}
/* Make sure input file exists. */
if( (inputFile = fopen(argv[1], O_RDONLY))) {
fprintf(stderr, "Input file doesn't exist.\n");
exit(-1);
}
/* Create output file, if it doesn't exist. Empty the file, if it exists. */
if((outputFile = fopen(argv[2], "a+"))) {
fclose(inputFile);
exit(-1);
}
/* Find the size of the input file. */
fileSize = fseek(inputFile, 0, SEEK_END);
/* Read input file and write to output file in reversed order.*/
for(pointer=fileSize-1; pointer>=0; pointer--) {
/*Write content in the buffer to the output file */
while(!feof(inputFile))
{
fgets(buffer, BUFFER_SIZE, inputFile); //reads 256 bytes at a time
fputs (buffer , outputFile );
}
}
fclose(inputFile);
fclose(outputFile);
return(0);
}
http://codelite.org/LiteEditor/ProjectSettings:
Project Settings >> General >> Command arguments
Right click on the project folder
Select project settings
General -> Execution -> Program Arguments

C program to use Unix System call for I/O [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 7 years ago.
Improve this question
My professor asked me to write a simple C program, then asked me to convert using Unix system calls. I have try changing the values around but nothing is working.
Requirement:
Write a new C program newcat, which performs exactly as oldcat, but uses the following UNIX system calls for I/O.
int read(int fd, char *buf, int n);
int write(int fd, char *buf, int n);
int open(char *name, int accessmode, int permission);
int close(int fd);
To open a file for read, you can use the symbolic constant O_RDONLY defined in fcntl.h header file to specify the accessmode. Simply pass 0 for permission. That is, the code will appear as follows:
fd = open (filename, O_RDONLY, 0);
You will need the following header files: sys/types.h, unistd.h and fcntl.h
#include <stdio.h>
/* oldcat: Concatenate files */
int main(int argc, char *argv[])
{
void filecopy(FILE *, FILE *); /* prototype for function */
int fd = open(*fp, O_RDONLy,0)
char *prog = argv[0]; /* program name for errors */
if (argc == 1) /* no args; copy standard input */
filecopy(0, 1);
else
while (--argc > 0)
if (fd == -1) {
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
return(-1);
} else {
filecopy(fp, 1);
fclose(fp);
}
return(0);
}
/* filecopy: copy file ifp to ofp */
void filecopy(FILE *ifp, FILE *ofp)
{
int c;
while ((c = getc(ifp)) != EOF)
putc(c, ofp);
}
Is this the write idea? It still won't compile:
#include <stdio.h>
/* oldcat: Concatenate files */
int main(int argc, char *argv[])
{
void filecopy(int ifp, int ifo);
int fd = open(*File,O_RDONLY,0); //is this correct?
char *prog = argv[0];
if (argc == 1) /* no args; copy standard input */
filecopy(0, 1); //is this correct?
else
while (--argc > 0)
if ((fd == -1) //is this correct?{
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
return(-1);
} else {
filecopy(*FILE, 1);//is this correct?
close(*FILE);//is this correct?
}
return(0);
}
/* filecopy: copy file ifp to ofp */
void filecopy(FILE *ifp, FILE *ofp)//NO CLUE HOW THIS SHOULD BE
{
int c;
while (c = read(fd ,&something,1)//What is &ch/&something?
putc(c, ofp);
}
Assuming your oldcat uses the C standard library calls (like fopen), it's a simple matter of mapping those to the UNIX calls.
At a high level:
fopen -> open
fread -> read
fwrite -> write
fclose -> close
For example, when opening your input file with:
FILE *fIn = fopen ("jargon.txt", "r");
you could instead use:
int inFd = open ("jargon.txt", O_RDONLY, 0);
The other calls are very similar, with similar functionality at the C standard library and UNIX system call levels. Details on those calls can usually be obtained from the manpages by entering something like man 2 open into your shell, or by plugging man open into your favourite search engine.
The only "tricky" mapping is if you've used getchar/putchar-style calls to do the actual reading and writing but that too becomes easy when you realise that (for example) reading a character is functionally identical to reading a block of size one:
int c = getc (fIn);
or:
char c;
int numread = read (inFd, &c, 1);
For your added question:
So to open a file: if (fd = open (fp, O_RDONLY, 0); ) == NULL)
Not quite. The fopen function returns NULL on error because it returns a pointer to a FILE structure.
The lower level calls use file descriptors rather than file handles, the former being a small integer value. So, instead of:
FILE *fp = fopen ("nosuchfile", "r");
if (fp == NULL) doSomethingIntelligent();
you would do something like:
int fd = open ("nosuchfile", O_RDONLY, 0);
if (fd == -1) doSomethingIntelligentUsing (errno);
In terms of what you need to change, the following comes off the top of my head (so may not be totally exhaustive but should be a very good start):
Add the required headers.
Stop using FILE* totally, using int instead.
Translate the fopen/fclose calls to open/close. This includes the function name, different parameters and different return types.
Modify filecopy to use file descriptors rather than file handles.
use 1 instead of stdout when calling filecopy (the latter is a FILE *).
As an example of how to do this, the following program testprog.c will read itself and echo each character to standard output:
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
int main (void) {
int num, ch, inFd;
// Open as read only.
inFd = open ("testprog.c", O_RDONLY, 0);
if (inFd == -1)
printf ("\n**Error %d opening file\n", errno);
// Get and output esach char until EOF/error.
while ((num = read (inFd, &ch, 1) != 0) == 1)
putchar (ch);
// Detect error.
if (num != 0)
printf ("\n**Error %d reading file\n", errno);
// Close file and exit.
close (inFd);
return 0;
}
Please note that documentation of linux sys calls is present in manual called man pages which you can access by using man command in bash shell in a linux system. As UNIX and Linux are quite similar (maybe equivalent) for the syscalls you are interested in you can check the man page for those syscalls in Linux.
All the four read, write, open and close linux syscalls are explained in man pages. You can access the manual page for these syscalls by typing below commands in shell:
man 2 read
man 2 write
man 2 open
man 2 close
These should probably guide you to right direction.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
/* newcat: Concatenate files */
int main(int argc, char *argv[])
{
void filecopy(int ifp, int ofp); /* prototype for function */
int fd;
char *prog = argv[0]; /* program name for errors */
if (argc == 1) /* no args; copy standard input */
filecopy(0,1);
else
while (--argc > 0)
fd = open(*++argv , O_RDONLY,0);
if ( fd == -1) {
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
return(-1);
} else {
filecopy(fd, 1);
close(fd);
}
return(0);
}
/* filecopy: copy file ifp to ofp */
void filecopy(int ifp, int ofp)
{
int c;
while (read(ifp,&c,ofp ) != 0)
write(ofp,&c,ofp);
}

How to feed my C Program in Terminal files for it to sequentially display?

I have created a program that sequentially displays on screen the contents of all of the files listed in the command line.
However, when I run it in terminal I can't actually get it to open any files I try to "feed" it.
Does anyone know how I can get it to work?
Here is an example of what I'm typing into Terminal on my mac:
"John_Smith-MacBook:Desktop smith_j$ "/Users/smith_j/Desktop/Question 3-28-13 5.10 PM/usr/local/bin/Question" helloworld.txt
Could not open file helloworld.txt for input"
This is the first day I've ever used Terminal so forgive me if the answer is very easy.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int byte;
FILE * source;
int filect;
if (argc == 1)
{
printf("Usage: %s filename[s]\n", argv[0]);
exit(EXIT_FAILURE);
}
for (filect = 1; filect < argc; filect++)
{
if ((source = fopen(argv[filect], "r")) == NULL)
{
printf("Could not open file %s for input\n", argv[filect]);
continue;
}
while ((byte = getc(source)) != EOF)
{
putchar(byte);
}
if (fclose(source) != 0)
printf("Could not close file %s\n", argv[1]);
}
return 0;
}
Look at the value of errno [probably with perror() ] so you know why it is failing to open.
Simple example:
perror("fopen failed:");
printf("errno = %d.\n", errno);
It will prefix the text version of the errno condition (library supplied) with "fopen Failed: ", then give the specific errno value.
The text of your command line above looks suspect, check to see if it is correct. Better yet, try calling your program with a simpler command line, for example, one file in the current directory with your binary.
Instead of all the long pathnames, put both the binary program and the data file in the same directory together. Then, from that location just do ./myprog filename.txt
That will have less chance of a typo interfering with execution.

Simulate the Linux command tee in C

I have to do the simulation of the command tee in C for Linux. How does tee work internally? It looks like a T-shaped pipe, so should I use a pipe? Is there a special kind of pipe?
tee takes stdin and copies the data stream to stdout as well as a file given as an option, it can be used in many very different situations.
An implementation in C is quite simple, just make a program that copies all data from stdin to stdout, but also use the same output statements for stdout on a file that you opened based on the command line argument.
basically in pseudo code:
file f = open(argv[1])
while (! end of file stdin) {
buffer = read stdin
write stdout buffer
write f buffer
}
close(f)
Note that you don't really have to do anything with pipes, your shell will sort out the pipes, the program only has to copy data from one stream to two others.
I finished the program!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
main(int argc, char *argv[]){
FILE *fp, *fp1;
char buffer;
if(argc != 4){
printf("\nError");
printf("\nSintaxis: tee [archivo1] [archivo2]\n");
exit(0);
}
if(strcmp(argv[1], "tee") == 0){
fp = fopen(argv[2], "r");
fp1 = fopen(argv[3], "w");
printf("\Content in %s:\n", argv[2]);
while(!feof(fp)){
buffer = fgetc(fp);
fputc(buffer, fp1);
printf("%c", buffer);
}
printf("\n\n%s received %s\n", argv[3], argv[2]);
fclose(fp);
fclose(fp1);
}
else
printf("\nThe first argument have to be tee\n");
}
Here is some code I wrote about 20 years ago to implement TEE in Windows. I have been using this with various batch files since then. Note the flush command at the end of each line.
#include <stdio.h>
#include <share.h>
int main (int argc, char * argv[])
{
if (argc < 2 )
{
printf ("Error: No output file name given, example: theCmd 2>&1 |ltee outputFileName \n");
return 1;
}
FILE *Out = _fsopen(argv[argc-1], "a", _SH_DENYWR);
if (NULL == Out)
{
char buf[300];
sprintf_s(buf, 300, "Error openning %s", argv[argc-1]);
perror(buf);
return 1;
}
int ch;
while ( EOF != (ch=getchar()))
{
putchar(ch);
putc(ch, Out);
if ( '\n' == ch )
fflush(Out);
}
_flushall();
fclose(Out);
return 0;
}

Resources