Link to home
Start Free TrialLog in
Avatar of errang
errangFlag for Afghanistan

asked on

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

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

Avatar of errang
errang
Flag of Afghanistan image

ASKER

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...
Avatar of errang

ASKER

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

Avatar of ozo
what is sh.h?
what is get_path?
Avatar of errang

ASKER

sh.h and get_path are simply functions that are used for which1, they just get all the available directories.
Avatar of errang

ASKER

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() */

Avatar of errang

ASKER

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...
//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);
  }
Avatar of errang

ASKER

wait... what are the arguments in:

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

and

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

ASKER

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);
Avatar of errang

ASKER

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?
   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
what do you want to do with the files?
what do you want to do with filename?
Avatar of errang

ASKER

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);
  }
Avatar of errang

ASKER

filename is the file I want to output the error to.
Avatar of errang

ASKER

What I need to be able to do with the program is to redirect any .o file into a .txt file or something.
ASKER CERTIFIED SOLUTION
Avatar of ozo
ozo
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of errang

ASKER

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?
Avatar of errang

ASKER

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
  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.
Avatar of errang

ASKER

that even applies to executable C code?
Avatar of errang

ASKER

Sweet, Thanks!
Avatar of errang

ASKER

This would work right?

char *path = current directory;
char *argv[]= name of executable;
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){
Avatar of errang

ASKER

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.. =(