?
Solved

how do I redirect the stdout and stderr from one file into another?

Posted on 2009-04-30
25
Medium Priority
?
396 Views
Last Modified: 2012-05-06
Hey, I don't have a lot of time to get this done... I'm trying to get the stderr from one file into another, this is what I have so far:

This program works for redirecting stdout from a file into another... but fails for stdin... could you please help me out?

Thanks in advance!!!
#include "sh.h"
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <pthread.h>
#include <fcntl.h>
 
char *which1(char *file);
 
int main(int argc, char **argv){
 
  pid_t pid, pid1;
  int ex, status;
  int fid = 0;
  int num = 0;
  int num1 = 0;
  char input[80];
  char *temp, *temp1;
  char *path, *cwd;
  char name[1000][80];
 
  cwd = getenv("PWD");
 
  printf("%s\n", cwd);
 
  printf(">>");
  fgets(input, 80, stdin);
  temp = strtok(input, " ");
 
  while(temp!=NULL){
    strcpy(name[num], temp);
    temp = strtok(NULL, " ");
    num++;
  }
 
  //temp1 = strtok(name[0], "\n");
  //printf("%s\n", temp1);
 
  pid = fork();
 
  if(pid < 0){
    printf("error!");
    exit(1);
  }
  else if(pid == 0){
    path = which1(cwd);
    argv[0] = strtok(name[0], "\n");
    argv[1] = NULL;
    //printf("%s\n", argv[0]);
 
    /*temp1 = strtok(name[2], "\n");
    fid = open(temp1, O_WRONLY | O_CREAT | O_APPEND, 0666);
    close(1);
    dup(fid);
    close(fid);*/
    ex = execv(path, argv);
 
  }
  else {
fid = open("/dev/tty",O_WRONLY);
    close(1);
    ex = execv(path, argv);
    dup(fid);
    close(fid);
    wait(NULL);
  }
 
  return(0);
}
 
//which1 takes the name of the file you are looking for as an argument.
//if it finds it, it appends that file to the directory it is in.
//if the file does not exist, it returns the default value, "Does not exist."
char *which1(char *file){
  DIR *pdir;
  struct pathelement *pathlist;
  struct dirent *pfile;
  char *return_file = "Does not exist.";
  char *temp;
  int str = 0;
 
 pathlist = get_path();
  pdir = opendir(pathlist->element);
 
  //printf("in here\n");
 
  while(pathlist!=NULL){
    pfile = readdir(pdir);
    while((pfile = readdir(pdir)) != NULL){
      str = strcmp(pfile->d_name, file);
      if(str == 0){
        return_file = strcat(pathlist->element, "/");
        return_file = strcat(return_file, pfile->d_name);
        return return_file;
      }
    }
    pathlist = pathlist->next;
    pdir = opendir(pathlist->element);
  }
 
  return return_file;
}

Open in new window

0
Comment
Question by:errang
  • 17
  • 8
25 Comments
 

Author Comment

by:errang
ID: 24267890
Well, that code would redirect the stdout if I removed the /* */ from around:

/*temp1 = strtok(name[2], "\n");
    fid = open(temp1, O_WRONLY | O_CREAT | O_APPEND, 0666);
    close(1);
    dup(fid);
    close(fid);*/

I really need to get this done quick... =(

this thing's supposed to work for stuff like:

./test1 >& test.txt

I can't figure out how to run a non-system call with execv, I tried putting the path as the current directory, and the argument as ./test1, but it didn't work.

Please, I need help...
0
 

Author Comment

by:errang
ID: 24267916
This version redirects the stdout of a command into a file... please help me with the stderr...

(sry bout the repetitiveness... i really really need help... this is due in < 12 hours...)
#include "sh.h"
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <pthread.h>
#include <fcntl.h>
 
char *which1(char *file);
 
int main(int argc, char **argv){
  
  pid_t pid, pid1;
  int ex, status;
  int fid = 0;
  int num = 0;
  int num1 = 0;
  char input[80];
  char *temp, *temp1;
  char *path;
  char name[1000][80];
 
  printf(">>");
  fgets(input, 80, stdin);
  temp = strtok(input, " ");
 
  while(temp!=NULL){
    strcpy(name[num], temp);
    temp = strtok(NULL, " ");
    num++;
  }
 
  pid = fork();
  
  if(pid < 0){
    printf("error!");
    exit(1);
  }
  else if(pid == 0){
    path = which1(name[0]);
    argv[1] = strtok(name[1], "\n");
    argv[2] = NULL;
    
    temp1 = strtok(name[3], "\n");
    fid = open(temp1, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    close(1);
    dup(fid);
    close(fid);
    ex = execv(path, argv);
    
  }
  else {
    fid = open("/dev/tty",O_WRONLY);
    close(1);
    ex = execv(path, argv);
    dup(fid);
    close(fid);
    wait(NULL);
  }
 
  return(0);
}
 
//which1 takes the name of the file you are looking for as an argument.
//if it finds it, it appends that file to the directory it is in.
//if the file does not exist, it returns the default value, "Does not exist."
char *which1(char *file){
  DIR *pdir;
  struct pathelement *pathlist;
  struct dirent *pfile;
  char *return_file = "Does not exist.";
  char *temp;
  int str = 0;
 
  pathlist = get_path();
  pdir = opendir(pathlist->element);
 
  //printf("in here\n");
 
  while(pathlist!=NULL){
    pfile = readdir(pdir);
    while((pfile = readdir(pdir)) != NULL){
      str = strcmp(pfile->d_name, file);
      if(str == 0){
        return_file = strcat(pathlist->element, "/");
        return_file = strcat(return_file, pfile->d_name);
        return return_file;
      }
    }
    pathlist = pathlist->next;
    pdir = opendir(pathlist->element);
  }
 
  return return_file;
}

Open in new window

0
 
LVL 85

Expert Comment

by:ozo
ID: 24267926
what is sh.h?
what is get_path?
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 

Author Comment

by:errang
ID: 24267939
sh.h and get_path are simply functions that are used for which1, they just get all the available directories.
0
 

Author Comment

by:errang
ID: 24267954
Here they are.

get_path

#include "get_path.h"

struct pathelement *get_path()
{
  /* path is a copy of the PATH and p is a temp pointer */
  char *path, *p;

  /* tmp is a temp point used to create a linked list and pathlist is a
     pointer to the head of the list */
  struct pathelement *tmp, *pathlist = NULL;

  p = getenv("PATH");/* get a pointer to the PATH env var.
                     make a copy of it, since strtok modifies the
                     string that it is working with... */
  path = malloc((strlen(p)+1)*sizeof(char));/* use malloc(3C) this time */
  strncpy(path, p, strlen(p));
  path[strlen(p)] = '\0';

  p = strtok(path, ":"); /* PATH is : delimited */
  do/* loop through the PATH */
    {/* to build a linked list of dirs */
      if ( !pathlist )/* create head of list */
      {
        tmp = calloc(1, sizeof(struct pathelement));
        pathlist = tmp;
      }
      else/* add on next element */
      {
        tmp->next = calloc(1, sizeof(struct pathelement));
        tmp = tmp->next;
      }
      tmp->element = p;
      tmp->next = NULL;
    } while ( p = strtok(NULL, ":") );

  return pathlist;
} /* end get_path() */


sh.h


#include "get_path.h"

int pid;
int sh( int argc, char **argv, char **envp);
int which(char *command, struct pathelement *pathlist);
int where(char *command, struct pathelement *pathlist);
void list ( char *dir );
void printenv(char **envp);

#define PROMPTMAX 32
#define MAXARGS 10

sh.c

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include "sh.h"

int sh( int argc, char **argv, char **envp )
{
  char *prompt = calloc(PROMPTMAX, sizeof(char));
  char *commandline = calloc(MAX_CANON, sizeof(char));
  char *command, *arg, *commandpath, *p, *pwd, *owd;
  char **args = calloc(MAXARGS, sizeof(char*));
  int uid, i, status, argsct, go = 1;
  struct passwd *password_entry;
  char *homedir;
  struct pathelement *pathlist;

  uid = getuid();
  password_entry = getpwuid(uid);               /* get passwd info */
  homedir = password_entry->pw_dir;/* Home directory to start
                              out with*/
     
  if ( (pwd = getcwd(NULL, PATH_MAX+1)) == NULL )
    {
      perror("getcwd");
      exit(2);
    }
  owd = calloc(strlen(pwd) + 1, sizeof(char));
  memcpy(owd, pwd, strlen(pwd));
  prompt[0] = ' '; prompt[1] = '\0';

  /* Put PATH into a linked list */
  pathlist = get_path();

  while ( go )
    {
      /* print your prompt */

      /* get command line and process */

      /* check for each built in command and implement */

      /*  else  program to exec */
      {
      /* find it */
      /* do fork(), execve() and waitpid() */

      //else
       //fprintf(stderr, "%s: Command not found.\n", args[0]);
      }
    }

return 0;
} /* sh() */

int which(char *command, struct pathelement *pathlist )
{
/* loop through pathlist until finding command and return it.  Return
   NULL when not found. */
 
  int i = 0;
  char *sep;
  char *s = "/";
  sep = strtok(pathlist->element, s);
  while(sep!=NULL){
    if(strcmp(sep, command)==0){
      i = 1;
      break;
    }
    sep = strtok(NULL, s);
  }

  return i;
} /* which() */

int where(char *command, struct pathelement *pathlist )
{
  /* similarly loop through finding all locations of command */
} /* where() */

void list ( char *dir )
{
  /* see man page for opendir() and readdir() and print out filenames for
     the directory passed */
} /* list() */

0
 

Author Comment

by:errang
ID: 24268080
Redirecting stderr from a regular command is easy right? all we need to do is:

    temp1 = strtok(name[3], "\n");
    fid = open(temp1, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    close(2);
    dup(fid);
    close(fid);
    ex = execv(path, argv);

Is redirecting stderr from the output of a file really that much harder? I can't seem to find anything good on it on google...
0
 
LVL 85

Expert Comment

by:ozo
ID: 24268112
//rather than ask what get_path.h is and trying to figure out what your code is doing, I'll just give an example of piping stderr into stdin
  int p2[2];
  pipe(p2);
  pid = fork();

  if(pid < 0){
    printf("error!");
    exit(1);
  }
  else if(pid == 0){
    char *path = "/usr/bin/perl";
    char *argv[]={"perl","-e","print STDERR qq'err\\n';",0};
    dup2(p2[1],2);
    close(p2[0]);
    ex = execv(path,argv);

  }
  else {
    char *path = "/bin/cat";
    char *argv[]={"cat","-ne",0};
    dup2(p2[0],0);
    close(p2[1]);
    ex = execv(path, argv);
    wait(NULL);
  }
0
 

Author Comment

by:errang
ID: 24268121
wait... what are the arguments in:

char *argv[]={"perl","-e","print STDERR qq'err\\n';",0};

and

char *argv[]={"cat","-ne",0};?
0
 

Author Comment

by:errang
ID: 24268133
hm... I'm guessing u'r returning stderr to the console with these?

char *path = "/bin/cat";
char *argv[]={"cat","-ne",0};
dup2(p2[0],0);
close(p2[1]);
ex = execv(path, argv);
wait(NULL);
0
 

Author Comment

by:errang
ID: 24268156
Hm... we need to add the open and close statements to this for it to work completely... right?

 else if(pid == 0){
    char *path = "/usr/bin/perl";
    char *argv[]={"perl","-e","print STDERR qq'err\\n';",0};
    p2[0] = open(filename, O_CREAT | O_TRUNC, 0666);
    close(2);
    dup2(p2[1],2);
    close(p2[0]);
    ex = execv(path,argv);

  }

Yes?
0
 
LVL 85

Expert Comment

by:ozo
ID: 24268177
   char *path = "/usr/bin/perl";
    char *argv[]={"perl","-e","print STDERR qq'err\\n';",0};
    execv(path,argv);
just runs a simple program that outputs to stderr

    char *path = "/bin/cat";
    char *argv[]={"cat","-ne",0};
    execv(path, argv);
just runs a simple program that inputs from stdin
for the purpose of demonstrating how two programs can be connected together
you can replace them with whatever programs you had wanted to run
0
 
LVL 85

Expert Comment

by:ozo
ID: 24268187
what do you want to do with the files?
0
 
LVL 85

Expert Comment

by:ozo
ID: 24268199
what do you want to do with filename?
0
 

Author Comment

by:errang
ID: 24268201
but wait... does that example pipe from one file to another?

I'm just wondering because the path variable is "/usr/bin/perl"

 int p2[2];
  pipe(p2);
  pid = fork();

  if(pid < 0){
    printf("error!");
    exit(1);
  }
  else if(pid == 0){
    char *path = "/usr/bin/perl";
    char *argv[]={"perl","-e","print STDERR qq'err\\n';",0};
    dup2(p2[1],2);
    close(p2[0]);
    ex = execv(path,argv);

  }
  else {
    char *path = "/bin/cat";
    char *argv[]={"cat","-ne",0};
    dup2(p2[0],0);
    close(p2[1]);
    ex = execv(path, argv);
    wait(NULL);
  }
0
 

Author Comment

by:errang
ID: 24268203
filename is the file I want to output the error to.
0
 

Author Comment

by:errang
ID: 24268212
What I need to be able to do with the program is to redirect any .o file into a .txt file or something.
0
 
LVL 85

Accepted Solution

by:
ozo earned 2000 total points
ID: 24268256
Sorry, I thought you wanted stderr to go into stdin of another program
here is a way to capture stdout and stderr into files
    int eid = open("errfile", O_WRONLY | O_CREAT | O_APPEND, 0666);
    int oid = open("outfile", O_WRONLY | O_CREAT | O_APPEND, 0666);
    if( !eid | !oid ){
      exit(1);
    }
    char *path = "/usr/bin/perl";
    char *argv[]={"perl","-e","print STDERR qq'err\\n'; print STDOUT qq'out\n';",0};
    dup2(eid,2);
    dup2(oid,1);
    execv(path,argv);
0
 

Author Comment

by:errang
ID: 24268293
hm... could you please explain these 2 variables?

char *path = "/usr/bin/perl";
char *argv[]={"perl","-e","print STDERR qq'err\\n'; print STDOUT qq'out\n';",0};

is perl the program that does that? or what?
0
 

Author Comment

by:errang
ID: 24268312
It's 6 am my time... so I'd better take a short nap before I pass out for 6 hours...

But Thanks in advance!!! =D
0
 
LVL 85

Expert Comment

by:ozo
ID: 24268318
  char *path = "/usr/bin/perl";
    char *argv[]={"perl","-e","print STDERR qq'err\\n'; print STDOUT qq'out\n';",0};
    execv(path,argv);
just runs a program that outputs to stderr and to stdout
you can replace it with whatever program you wanted to run from which you wanted to capture stderr or stdout.
0
 

Author Comment

by:errang
ID: 24268327
that even applies to executable C code?
0
 

Author Comment

by:errang
ID: 24268332
Sweet, Thanks!
0
 

Author Comment

by:errang
ID: 24268338
This would work right?

char *path = current directory;
char *argv[]= name of executable;
0
 
LVL 85

Expert Comment

by:ozo
ID: 24268361
int execv(const char *path, char *const argv[]);

path is the  pathname of a file which is to be executed.

argv will be passed to the process where it will be read as argv in
int main(int argc, char **argv){
0
 

Author Comment

by:errang
ID: 24271619
hm... am I doing something wrong here?

 temp1 = strtok(name[2], "\n");
    err_fid = open(name[0], O_WRONLY | O_CREAT | O_APPEND, 0666);
    fid = open(temp1, O_WRONLY | O_CREAT | O_APPEND, 0666);
    dup2(err_fid, 2);
    dup2(fid, 1);
    ex = execv(path, argv);

It doesn't seem to be working.. =(
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

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…
Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.

839 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