2016-06-24 3 views
0

Hey, ich benutze den Sommer, um Unix und c zu lernen. Ich möchte ein aktuelles Programm erweitern, indem ich Pipes implementiere. Wie kann ich meinen Code so ändern, dass er "|" analysiert? Ich werde execvp verwenden, um Befehle auszuführen. In der Shell, wenn ich cat file | tr a A geben mag ich cat und tr spalten, so dass es führt beide hier mein aktueller CodeC: Wie man "|"

numBytes = read(0, buffer, INPUT_BUFFER_SIZE); 
char *token; 
inputBuffer[numBytes] = '\0'; 

token = strtok(buffer, " \n"); 

int i = 0; 
while(token != NULL){ 
    userInput[i] = token; 
    token = strtok(NULL, " \n"); 
    ++i; 
} 
userInput[i] = 0; 
+0

Sie haben mehrere undefinierte Variablen und Makros. Wenn das '|' sogar so weit geht, dass es sich in der angegebenen Zeichenfolge befindet, müssen Sie es in die Trennzeichen einfügen, z. B. "| \ n" '. Ich habe den 'Raum' entfernt, da Ihre Beispiele ein Leerzeichen in den Token enthalten, die Sie trennen möchten. Es ist jedoch ziemlich unklar. –

+1

@WeatherVane Wenn er '|' in die Trennzeichen schreibt, kann er nicht feststellen, ob das Trennzeichen whitespace oder pipe ist, da 'strtok()' das Trennzeichen aus der Eingabezeichenfolge entfernt. – Barmar

+0

Angenommen, Sie halten es einfach, so dass der Benutzer Leerzeichen um das Pipe-Symbol setzen muss, müssen Sie nur etwas wie "if (strcmp (token, |)" == 0) verwenden, um zu erkennen, ob sie eingegeben wurden ein Rohr. – Barmar

Antwort

0

Sie unser Programm verwenden kann pipeline.c etwas zeigen Ihnen, wie Rohre zu implementieren. Sie spalten eine Pipeline who | awk '{print $1}' | sort | uniq -c | sort -n und Verwendung Arrays die Pipeline auszuführen:

static char *cmd0[] = {"who", 0}; 
static char *cmd1[] = {"awk", "{print $1}", 0}; 
static char *cmd2[] = {"sort", 0}; 
static char *cmd3[] = {"uniq", "-c", 0}; 
static char *cmd4[] = {"sort", "-n", 0}; 

Wenn Sie den Befehl in Arrays wie oben geteilt haben, können Sie Code wie unten verwenden.

#define _XOPEN_SOURCE 500 

/* 
* pipeline.c 
* One way to create a pipeline of N processes using execvp 
* written 2015 by: Jonathan Leffler 
* test, packaging and maintenance by Niklas Rosencrantz [email protected] 
*/

#ifndef STDERR_H_INCLUDED 
#define STDERR_H_INCLU, DED 
#endif /* STDERR_H_INCLUDED */ 

/* pipeline.c */ 
#include <assert.h> 
#include <stdio.h> 
#include <sys/wait.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <memory.h> 
#include <errno.h> 

typedef int Pipe[2]; 
/* exec_nth_command() and exec_pipe_command() are mutually recursive */ 
static void exec_pipe_command(int ncmds, char ***cmds, Pipe output); 
static void err_vsyswarn(char const *fmt, va_list args) 
{ 
    int errnum = errno; 
    //fprintf(stderr, "%s:%d: ", arg0, (int)getpid()); 
    vfprintf(stderr, fmt, args); 
    if (errnum != 0) 
     fprintf(stderr, " (%d: %s)", errnum, strerror(errnum)); 
    putc('\n', stderr); 
} 

static void err_syswarn(char const *fmt, ...) { 
    va_list args; 
// va_start(args, fmt); 
    err_vsyswarn(fmt, args); 
    // va_end(args); 
} 

static void err_sysexit(char const *fmt, ...) 
{ 
    va_list args; 
    //va_start(args, fmt); 
    err_vsyswarn(fmt, args); 
    //va_end(args); 
    exit(1); 
} 

/* With the standard output plumbing sorted, execute Nth command */ 
static void exec_nth_command(int ncmds, char ***cmds) { 
    assert(ncmds >= 1); 
    if (ncmds > 1) { 
     pid_t pid; 
     Pipe input; 
     if (pipe(input) != 0) 
      err_sysexit("Failed to create pipe"); 
     if ((pid = fork()) < 0) 
      err_sysexit("Failed to fork"); 
     if (pid == 0) { 
      /* Child */ 
      exec_pipe_command(ncmds - 1, cmds, input); 
     } 
     /* Fix standard input to read end of pipe */ 
     dup2(input[0], 0); 
     close(input[0]); 
     close(input[1]); 
    } 
    execvp(cmds[ncmds - 1][0], cmds[ncmds - 1]); 
    err_sysexit("Failed to exec %s", cmds[ncmds - 1][0]); 
    /*NOTREACHED*/ 
} 
/* exec_nth_command() and exec_pipe_command() are mutually recursive */ 
/* Given pipe, plumb it to standard output, then execute Nth command */ 
static void exec_pipe_command(int ncmds, char ***cmds, Pipe output) { 
    assert(ncmds >= 1); 
    /* Fix stdout to write end of pipe */ 
    dup2(output[1], 1); 
    close(output[0]); 
    close(output[1]); 
    exec_nth_command(ncmds, cmds); 
} 

/* Execute the N commands in the pipeline */ 
static void exec_pipeline(int ncmds, char ***cmds) { 
    assert(ncmds >= 1); 
    pid_t pid; 
    if ((pid = fork()) < 0) 
     err_syswarn("Failed to fork"); 
    if (pid != 0) 
     return; 
    exec_nth_command(ncmds, cmds); 
} 

static void exec_arguments(int argc, char **argv) 
{ 
    /* Split the command line into sequences of arguments */ 
    /* Break at pipe symbols as arguments on their own */ 
    char **cmdv[argc/2];   // Way too many 
    char *args[argc+1]; 
    int cmdn = 0; 
    int argn = 0; 

    cmdv[cmdn++] = &args[argn]; 
    for (int i = 1; i < argc; i++) 
    { 
     char *arg = argv[i]; 
     if (strcmp(arg, "|") == 0) 
     { 
      if (i == 1) 
       err_sysexit("Syntax error: pipe before any command"); 
      if (args[argn-1] == 0) 
       err_sysexit("Syntax error: two pipes with no command between"); 
      arg = 0; 
     } 
     args[argn++] = arg; 
     if (arg == 0) 
      cmdv[cmdn++] = &args[argn]; 
    } 
    if (args[argn-1] == 0) 
     err_sysexit("Syntax error: pipe with no command following"); 
    args[argn] = 0; 
    exec_pipeline(cmdn, cmdv); 
} 
/* who | awk '{print $1}' | sort | uniq -c | sort -n */ 
static char *cmd0[] = {"who", 0}; 
static char *cmd1[] = {"awk", "{print $1}", 0}; 
static char *cmd2[] = {"sort", 0}; 
static char *cmd3[] = {"uniq", "-c", 0}; 
static char *cmd4[] = {"sort", "-n", 0}; 

static char **cmds[] = {cmd0, cmd1, cmd2, cmd3, cmd4}; 
static int ncmds = sizeof(cmds)/sizeof(cmds[0]); 

int main(int argc, char **argv) { 
    /* The most basic example */ 
    char *execArgs[] = { "ls", "-al", 0 }; 
    execvp("ls", execArgs); 

    if (argc == 1) { 
     /* Run the built in pipe-line */ 
     exec_pipeline(ncmds, cmds); 
    } else { 
     /* Run command line specified by user */ 
     exec_arguments(argc, argv); 
    } 
    return(0); 
}