7

In this C program

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main()
{
    int file = open("Result", O_CREAT|O_WRONLY, S_IRWXU);

    dup2(stdout, file);
    system("ls -l");

    return 0;
}

I'm trying to redirect the output of system() to a file, for that i have used dup2 but it is not working.

What's wrong with this code?
and, please tell me if there is any better way to do this? (without using > at the terminal )

user4035
  • 22,508
  • 11
  • 59
  • 94
Eight
  • 4,194
  • 5
  • 30
  • 51

5 Answers5

7

stdout is a FILE * pointer of the standard output stream. dup2 expects file descriptor, also you've messed up the parameters order. Use

dup2(file, 1);

instead.

On the better-way-to-do-this part. This way is bad because you probably want to restore your standard output after this system call completes. You can do this in a variety of ways. You can dup it somewhere and then dup2 it back (and close the dupped one). I personally don't like writing own cat implementations as suggested in other answers. If the only thing you want is redirecting a single shell command with system to a file in the filesystem, then probably the most direct and simple way is to construct the shell command to do this like

system("ls -l > Result");

But you have to be careful if filename (Result) comes from user input as user can supply something like 'Result; rm -rf /*' as the filename.

Also, on the topic of security, you should consider specifying the full path to ls as suggested in the comments:

system("/bin/ls -l > Result");
unkulunkulu
  • 11,576
  • 2
  • 31
  • 49
  • 1
    I edited your post to include an absolute path to ls in your example. – Wug Jun 25 '12 at 18:23
  • Reverted edit because the OP runs `"ls"` and this would change the meaning of the system call. The question is also unrelated to absolute or relative paths. I think it's better to ask @unkulunkulu if he would like to revise his answer. – Andomar Jun 25 '12 at 18:35
  • @Andomar, actually, I accepted the edit, but anyway, both your points are valid, I don't see a difference :) Wug, thanks for suggestion, it will be seen in the comments anyway. – unkulunkulu Jun 25 '12 at 18:36
  • @unkulunkulu: don't hesitate to reverse my change if you agree with Wug. You can do so by clicking on the "edited X mins ago" and choosing "revert" for the appropriate revision. – Andomar Jun 25 '12 at 18:39
  • 1
    Calling system without specifying an absolute path is generally a very bad idea because of the potential for tricksy individuals to break your program by playing with PATH. Not a good mistake for a beginner to get into the habit of. Hence, my edit. – Wug Jun 25 '12 at 20:34
5

The simple thing is to use > indeed:

#include <stdio.h>
int main()
{
    system("ls -l > /some/file");

    return 0;
}

An alternative is using popen(), something along the lines of

   #include <stdio.h>
   #include <stdlib.h>
   main()
   {
           char *cmd = "ls -l";
           char buf[BUFSIZ];
           FILE *ptr, *file;

           file = fopen("/some/file", "w");
           if (!file) abort();
           if ((ptr = popen(cmd, "r")) != NULL) {
                   while (fgets(buf, BUFSIZ, ptr) != NULL)
                           fprintf(file, "%s", buf);
                   pclose(ptr);
           }
           fclose(file);
           return 0;
   }
johannes
  • 15,807
  • 3
  • 44
  • 57
4

You should use the popen() library function and read chunks of data from the returned FILE * and write them to whatever output file you like.

Reference.

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149
trojanfoe
  • 120,358
  • 21
  • 212
  • 242
0

use dup instead of dup2. dup creates a alias file descriptor, which value should be always the smallest available file descriptor.

new_fd = dup(file); - In this statement file might be having the value 3 (because stdin is 0, stdout is 1 and stderr is 2). so new_fd will be 4

If you want to redirect stdout into file. Then do as below.

close(stdout);
new_fd = dup(file);

Now dup will return 1 as the alias for the file descriptor, because we closed stdout so opened file descriptors are 0,2,3 and 1 is smallest available file descriptor.

If you are using dup2 means, dup2(file,1); - do like this

rashok
  • 12,790
  • 16
  • 88
  • 100
  • Using `dup()` instead of `dup2()` is _only_ if you don't care where the duplicate is placed. If you care, use `dup2()` -- that's its explicit purpose! If instead you simply hope for the best, as this answer does, it will work fine until one day the pattern breaks and you won't have any idea why it fails. Those make for some aggravating late night debug sessions which could have been avoided by simply doing it the right way from the start. – mah Jan 19 '14 at 13:13
0

The other answers are valid but, since you asked about a way to redirect the system()output without the use of > operator in terminal, I would recommend using the FILE *freopen(const char *filename, const char *mode, FILE *stream) function (that is part of the stdio.h header). This is what best represents the > operator in my opinion.

Your code could become something like:

# include <stdio.h>
# include <stdlib.h>

int main(void){
   
   char line[1024];
   FILE *handle = freopen("result.txt", "w", stdout);
   if(!handle)  
     exit(EXIT_FAILURE); //file didn't open
   
   sprintf(line, "ls -l");
   system(line);
   return 0;
}

I would also suggest to first put the command into a buffer and then call system(). This is done in order to simplify scenarios where you need to execute the same command with different parameters.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Pit
  • 11
  • 3