Wie

2016-04-27 17 views
3

So zum Rohr in C, würde Ich mag die folgende Befehlszeile in C tun:Wie

ps -eo user,pid,ppid 2> log.txt | grep user 2>>log.txt | sort -nk2 > out.txt 

Aber ich bin nicht sicher, wie überhaupt, wie der Code ... ich sein könnte bin verwirrt bei wie muss ich die ausgabe eines befehls in eine datei schreiben, die richtige und die fehlerausgabe ...

Auch ich habe keine Ahnung wie ich die Rohrleitungen strukturieren soll und was wann zu tun ist pid == -1 oder wenn pid> 0 ...

Mein Code unten:

int main(){ 

    int fd0[2], fd1[2], pid0, pid1; 

    pipe(fd0); 
    pid0 = fork(); 
    if (pid == 0){ 
     close(1); 
     dup(fd0[0]); 
     fd_file= open(“./out.txt”, O_WRONLY | O_CREAT | O_TRUNC, 00600); 
     execl("sort","-nk2",">fd_file"); 
     pipe(fd1); 
     pid1 = fork(); 
     if (pid1 == 0){ 
      close(1); 
      dup(fd1[0]); 
      ...? 
     } 

    } 
    else if (pid == -1){ 
     perror("ERROR AT SORT!\n"); 
     exit(1); 
    } 

    return 0; 
} 
+1

Zum Behandeln von Fehlern ist es wahrscheinlich am besten zu beenden (mit Rückkehr in 'main()' oder 'exit()'). – jdarthenay

+0

Legen Sie keine neue Zeile am Ende der an "perror" übergebenen Zeichenfolge an. 'perror' wird Ihre Zeichenfolge gefolgt von einem': 'ausgeben, und es sieht seltsam aus, wenn der Doppelpunkt in einer neuen Zeile beginnt. –

+1

Die nächste Zeile nach execl wird nur ausgeführt, wenn execl fehlschlägt. – cdarke

Antwort

1

Während die Verkettung von zwei Befehlen einfach erscheinen kann, ist es ein bisschen schwieriger, mehr zu verketten. Ich gebe ein Programm, das leicht verallgemeinert werden kann, um beliebig viele Befehle zu verketten. Ich bevorzuge es, den ersten Prozess als ein Elternteil aller Prozesse zu behalten.

Bitte lesen Sie die Kommentare für detailliertere Erklärungen.

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <fcntl.h> 


// Better to use define for constants 
#define SUB_PROCESSES_NUMBER 2 
#define FILE_OUT "out.txt" 
#define FILE_LOGS "log.txt" 

char *command0[] = {"ps", "-eo" "user,pid,ppid", NULL}; 
char *command1[] = {"grep", "^user", NULL}; // "^user" matches lines starting with "user" 
char *command2[] = {"sort", "-nk2", NULL}; 
char **commands[SUB_PROCESSES_NUMBER + 1] = {command0, command1, command2}; 

int main(){ 
    pid_t pid[SUB_PROCESSES_NUMBER]; // good practice: fork() result is pid_t, not int 
    int fd[SUB_PROCESSES_NUMBER][2]; 

    // I recommend opening files now, so if you can't you won't create unecessary processes 
    int fd_file_out = open(FILE_OUT, O_WRONLY | O_CREAT | O_TRUNC, 00600); 
    if (fd_file_out < 0) 
    { 
     perror("open(" FILE_OUT ")"); 
     return 2; 
    } 

    int fd_file_logs = open(FILE_LOGS, O_WRONLY | O_CREAT | O_TRUNC, 00600); 
    if (fd_file_logs < 0) 
    { 
     perror("open(" FILE_LOGS ")"); 
     close(fd_file_out); // Not necessary, but I like to do it explicitly 
     return 2; 
    } 

    for (int i = 0; i < SUB_PROCESSES_NUMBER; i++) // If you decide to add more steps, this loop will be handy 
    { 
     if (pipe(fd[i]) < 0) 
     { 
      perror("pipe"); 
      close(fd_file_out); 
      close(fd_file_logs); 
      if (i > 0) 
      { 
       close(fd[i - 1][0]); 
      } 
      return 2; 
     } 

     pid[i] = fork(); 
     if (pid[i] < 0) 
     { 
      perror("fork()"); 
      close(fd_file_out); 
      close(fd_file_logs); 
      if (i > 0) 
      { 
       close(fd[i - 1][0]); 
      } 
      close(fd[i][0]); 
      close(fd[i][1]); 
      return 2; 
     } 

     if (pid[i] == 0) 
     { 
      close(fd[i][0]); // First thing to do: close pipes and files you don't need any more 
      close(fd_file_out); 

      close(1); 
      dup(fd[i][1]); 
      close(fd[i][1]); // duplicated pipes are not useful any more 

      close(2); // Also need to redirect stderr 
      dup(fd_file_logs); 
      close(fd_file_logs); 

      if (i > 0) 
      { 
       close(0); // Also need to redirect stdin if this is not first process 
       dup(fd[i - 1][0]); 
       close(fd[i - 1][0]); 
      } 

      execvp(commands[i][0], commands[i]); // In a loop, we need a execv()/execvp()/execvpe() call 
      return 2; // Should not be reached; 
     } 

     // sub process either did execvp() or return, he won't reach this point 
     close(fd[i][1]); 
     if (i > 0) 
     { 
      close(fd[i - 1][0]); 
     } 
    } 

    close(fd_file_logs); 

    close(0); 
    dup(fd[SUB_PROCESSES_NUMBER - 1][0]); 
    close(fd[SUB_PROCESSES_NUMBER - 1][0]); 

    close(1); 
    dup(fd_file_out); 
    close(fd_file_out); 

    execvp(commands[SUB_PROCESSES_NUMBER][0], commands[SUB_PROCESSES_NUMBER]); 
    perror("execvp"); 
    return 2; 
}