هل هذا متعددة الأنابيب التعليمات البرمجية في C منطقي ؟

StackOverflow https://stackoverflow.com/questions/948221

  •  09-09-2019
  •  | 
  •  

سؤال

لقد خلق سؤال حول هذا بضعة أيام.الحل هو شيء في خطوط ما اقترح في الجواب المقبول.بيد صديق جاء مع الحل التالي:

يرجى ملاحظة أن الرمز قد تم تحديثه عدة مرات (راجع تحرير المراجعات) لتعكس اقتراحات في الإجابات أدناه.إذا كنت تنوي إعطاء إجابة جديدة, يرجى القيام بذلك مع هذا القانون الجديد في العقل و ليس القديم الذي كان الكثير من المشاكل.

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

int main(int argc, char *argv[]){
    int fd[2], i, aux, std0, std1;

    do {
        std0 = dup(0); // backup stdin
        std1 = dup(1); // backup stdout

        // let's pretend I'm reading commands here in a shell prompt
        READ_COMMAND_FROM_PROMPT();

        for(i=1; i<argc; i++) {
            // do we have a previous command?
            if(i > 1) {
                dup2(aux, 0);
                close(aux);
            }

            // do we have a next command?
            if(i < argc-1) {
                pipe(fd);

                aux = fd[0];
                dup2(fd[1], 1);
                close(fd[1]);
            }

            // last command? restore stdout...
            if(i == argc-1) {
                dup2(std1, 1);
                close(std1);
            }

            if(!fork()) {
                // if not last command, close all pipe ends
                // (the child doesn't use them)
                if(i < argc-1) {
                    close(std0);
                    close(std1);
                    close(fd[0]);
                }

                execlp(argv[i], argv[i], NULL);
                exit(0);
            }
        }

        // restore stdin to be able to keep using the shell
        dup2(std0, 0);
        close(std0);
    }

    return 0;
}

هذا يحاكي سلسلة من الأوامر من خلال أنابيب في باش, على سبيل المثال:cmd1 | cmd2 | ...| cmd_n.أقول "محاكاة" ، لأنه ، كما ترون ، فإن الأوامر قراءة الواقع من الحجج.فقط وقت الفراغ الترميز بسيطة قذيفة موجه...

بالطبع هناك بعض القضايا إلى إصلاح وإضافة مثل معالجة الخطأ ولكن هذه ليست النقطة هنا.أعتقد أنا الحصول على رمز لكنه لا يزال يجعل لي الكثير من الخلط كيف يعمل كل شيء.

أنا في عداد المفقودين شيء أو هذا يعمل حقا انها جميلة ونظيفة الحل لحل هذه المشكلة ؟ إذا لا يمكن لأي شخص أن لي نقطة حاسمة مشاكل هذا الرمز ؟

هل كانت مفيدة؟

المحلول

تبدو معقولة ، على الرغم من أنه يحتاج حقا إلى إصلاح تسرب std و aux إلى الأطفال بعد حلقة ، و الوالد الأصلي stdin فقدت إلى الأبد.

هذا ربما يكون أفضل مع لون...

./a.out foo bar baz <stdin >stdout
std = dup(stdout)     ||     |+==========================std
                      ||     ||                          ||
pipe(fd)              ||     ||    pipe1[0] -- pipe0[1]  ||
                      ||     ||       ||          ||     ||
aux = fd[0]           ||     ||      aux          ||     ||
                      ||     XX       ||          ||     ||
                      ||      /-------++----------+|     ||
dup2(fd[1], 1)        ||     //       ||          ||     ||
                      ||     ||       ||          ||     ||
close(fd[1])          ||     ||       ||          XX     ||
                      ||     ||       ||                 ||
fork+exec(foo)        ||     ||       ||                 ||
                      XX     ||       ||                 ||
                       /-----++-------+|                 ||
dup2(aux, 0)          //     ||       ||                 ||
                      ||     ||       ||                 ||
close(aux)            ||     ||       XX                 ||
                      ||     ||                          ||
pipe(fd)              ||     ||    pipe2[0] -- pipe2[1]  ||
                      ||     ||       ||          ||     ||
aux = fd[0]           ||     ||      aux          ||     ||
                      ||     XX       ||          ||     ||
                      ||      /-------++----------+|     ||
dup2(fd[1], 1)        ||     //       ||          ||     ||
                      ||     ||       ||          ||     ||
close(fd[1])          ||     ||       ||          XX     ||
                      ||     ||       ||                 ||
fork+exec(bar)        ||     ||       ||                 ||
                      XX     ||       ||                 ||
                       /-----++-------+|                 ||
dup2(aux, 0)          //     ||       ||                 ||
                      ||     ||       ||                 ||
close(aux)            ||     ||       XX                 ||
                      ||     ||                          ||
pipe(fd)              ||     ||    pipe3[0] -- pipe3[1]  ||
                      ||     ||       ||          ||     ||
aux = fd[0]           ||     ||      aux          ||     ||
                      ||     XX       ||          ||     ||
                      ||      /-------++----------+|     ||
dup2(fd[1], 1)        ||     //       ||          ||     ||
                      ||     ||       ||          ||     ||
close(fd[1])          ||     ||       ||          XX     ||
                      ||     XX       ||                 ||
                      ||      /-------++-----------------+|
dup2(std, 1)          ||     //       ||                 ||
                      ||     ||       ||                 ||
fork+exec(baz)        ||     ||       ||                 ||
  • foo يحصل stdin=stdin, stdout=pipe1[1]
  • bar يحصل stdin=pipe1[0], stdout=pipe2[1]
  • baz يحصل stdin=pipe2[0], stdout=stdout

اقتراحي يختلف في أنه يتجنب تغيير اسم الوالد stdin و stdout, فقط التلاعب بها داخل الطفل ، وعدم تسرب أي FDs.انها قليلا من الصعب الرسم البياني ، على الرغم من.

for cmd in cmds
    if there is a next cmd
        pipe(new_fds)
    fork
    if child
        if there is a previous cmd
            dup2(old_fds[0], 0)
            close(old_fds[0])
            close(old_fds[1])
        if there is a next cmd
            close(new_fds[0])
            dup2(new_fds[1], 1)
            close(new_fds[1])
        exec cmd || die
    else
        if there is a previous cmd
            close(old_fds[0])
            close(old_fds[1])
        if there is a next cmd
            old_fds = new_fds
parent
    cmds = [foo, bar, baz]
    fds = {0: stdin, 1: stdout}

cmd = cmds[0] {
    there is a next cmd {
        pipe(new_fds)
            new_fds = {3, 4}
            fds = {0: stdin, 1: stdout, 3: pipe1[0], 4: pipe1[1]}
    }

    fork             => child
                        there is a next cmd {
                            close(new_fds[0])
                                fds = {0: stdin, 1: stdout, 4: pipe1[1]}
                            dup2(new_fds[1], 1)
                                fds = {0: stdin, 1: pipe1[1], 4: pipe1[1]}
                            close(new_fds[1])
                                fds = {0: stdin, 1: pipe1[1]}
                        }
                        exec(cmd)

    there is a next cmd {
        old_fds = new_fds
            old_fds = {3, 4}
    }
}

cmd = cmds[1] {
    there is a next cmd {
        pipe(new_fds)
            new_fds = {5, 6}
            fds = {0: stdin, 1: stdout, 3: pipe1[0], 4: pipe1[1],
                                        5: pipe2[0], 6: pipe2[1]}
    }

    fork             => child
                        there is a previous cmd {
                            dup2(old_fds[0], 0)
                                fds = {0: pipe1[0], 1: stdout,
                                       3: pipe1[0], 4: pipe1[1],
                                       5: pipe2[0], 6: pipe2[1]}
                            close(old_fds[0])
                                fds = {0: pipe1[0], 1: stdout,
                                                    4: pipe1[1],
                                       5: pipe2[0]  6: pipe2[1]}
                            close(old_fds[1])
                                fds = {0: pipe1[0], 1: stdout,
                                       5: pipe2[0], 6: pipe2[1]}
                        }
                        there is a next cmd {
                            close(new_fds[0])
                                fds = {0: pipe1[0], 1: stdout, 6: pipe2[1]}
                            dup2(new_fds[1], 1)
                                fds = {0: pipe1[0], 1: pipe2[1], 6: pipe2[1]}
                            close(new_fds[1])
                                fds = {0: pipe1[0], 1: pipe1[1]}
                        }
                        exec(cmd)

    there is a previous cmd {
        close(old_fds[0])
            fds = {0: stdin, 1: stdout,              4: pipe1[1],
                                        5: pipe2[0], 6: pipe2[1]}
        close(old_fds[1])
            fds = {0: stdin, 1: stdout, 5: pipe2[0], 6: pipe2[1]}
    }

    there is a next cmd {
        old_fds = new_fds
            old_fds = {3, 4}
    }
}

cmd = cmds[2] {
    fork             => child
                        there is a previous cmd {
                            dup2(old_fds[0], 0)
                                fds = {0: pipe2[0], 1: stdout,
                                       5: pipe2[0], 6: pipe2[1]}
                            close(old_fds[0])
                                fds = {0: pipe2[0], 1: stdout,
                                                    6: pipe2[1]}
                            close(old_fds[1])
                                fds = {0: pipe2[0], 1: stdout}
                        }
                        exec(cmd)

    there is a previous cmd {
        close(old_fds[0])
            fds = {0: stdin, 1: stdout,              6: pipe2[1]}
        close(old_fds[1])
            fds = {0: stdin, 1: stdout}
    }
}

تحرير

تحديث الخاص بك رمز لا إصلاح السابقة FD التسريبات لكن يضيف واحد:أنت الآن تسريب std0 إلى الأطفال.كما يقول جون, وربما هذا هو ليس خطرا على معظم البرامج...ولكن لا يزال يجب أن تكتب أفضل تصرف قذيفة من هذا.

حتى لو كان مؤقت, وأود أن نوصي بشدة ضد تغيير اسم الخاص بك قذيفة القياسية في/خارج/err (0/1/2), فقط تفعل ذلك في الطفل قبل exec.لماذا ؟ افترض يمكنك إضافة بعض printf التصحيح في الوسط ، أو تحتاج إلى إنقاذ بسبب حالة الخطأ.عليك أن تكون في ورطة إذا كنت لا تنظيف الفوضى معيار واصفات الملف الأول.يرجى من أجل وجود الأشياء تعمل كما هو متوقع حتى في سيناريوهات غير متوقعة, لا الوحل معهم حتى كنت في حاجة إليها.


تحرير

كما ذكرت في تعليقات أخرى ، تقسيمه إلى أجزاء أصغر يجعل من أسهل بكثير لفهم.هذا المساعد صغير يجب أن تكون مفهومة بسهولة و خالية من الشوائب:

/* cmd, argv: passed to exec
 * fd_in, fd_out: when not -1, replaces stdin and stdout
 * return: pid of fork+exec child
 */
int fork_and_exec_with_fds(char *cmd, char **argv, int fd_in, int fd_out) {
    pid_t child = fork();
    if (fork)
        return child;

    if (fd_in != -1 && fd_in != 0) {
        dup2(fd_in, 0);
        close(fd_in);
    }

    if (fd_out != -1 && fd_in != 1) {
        dup2(fd_out, 1);
        close(fd_out);
    }

    execvp(cmd, argv);
    exit(-1);
}

كما أن هذا:

void run_pipeline(int num, char *cmds[], char **argvs[], int pids[]) {
    /* initially, don't change stdin */
    int fd_in = -1, fd_out;
    int i;

    for (i = 0; i < num; i++) {
        int fd_pipe[2];

        /* if there is a next command, set up a pipe for stdout */
        if (i + 1 < num) {
            pipe(fd_pipe);
            fd_out = fd_pipe[1];
        }
        /* otherwise, don't change stdout */
        else
            fd_out = -1;

        /* run child with given stdin/stdout */
        pids[i] = fork_and_exec_with_fds(cmds[i], argvs[i], fd_in, fd_out);

        /* nobody else needs to use these fds anymore
         * safe because close(-1) does nothing */
        close(fd_in);
        close(fd_out);

        /* set up stdin for next command */
        fd_in = fd_pipe[0];
    }
}

يمكنك أن ترى باش's execute_cmd.c#execute_disk_command يتم استدعاء من execute_cmd.c#execute_pipeline, xsh's process.c#process_run يتم استدعاء من jobs.c#job_run, و حتى كل واحد من BusyBox's مختلف صغيرة و الحد الأدنى قذائف يقسم لهم.

نصائح أخرى

المشكلة الرئيسية هي أن تقوم بإنشاء مجموعة من الأنابيب ولا تتأكد من إغلاق جميع النهايات بشكل صحيح. إذا قمت بإنشاء أنبوب، فستحصل على واصفات الملف؛ إذا كنت شوكة، فسيكون لديك أربعة واصفات ملف. اذا أنت dup() أو dup2() نهاية واحدة من الأنبوب إلى واصف قياسي، تحتاج إلى إغلاق طرفي الأنبوب - يجب أن تكون واحدة على الأقل من الإغلاق بعد عملية DUP () أو DUP2 ().


النظر في واصفات الملف المتاحة للأمر الأول (على افتراض أن هناك ما لا يقل عن اثنين - شيء يجب معالجته بشكل عام (لا pipe() أو إعادة توجيه الإدخال / الإخراج اللازمة مع أمر واحد فقط)، لكنني أدرك أن معالجة الأخطاء يتم إلغاؤها للحفاظ على الكود مناسب لذلك):

    std=dup(1);    // Likely: std = 3
    pipe(fd);      // Likely: fd[0] = 4, fd[1] = 5
    aux = fd[0];
    dup2(fd[1], 1);
    close(fd[1]);  // Closes 5

    if (fork() == 0) {
         // Need to close: fd[0] aka aux = 4
         // Need to close: std = 3
         close(fd[0]);
         close(std);
         execlp(argv[i], argv[i], NULL);
         exit(1);
    }

لاحظ أنه بسبب fd[0] لا يتم إغلاقه في الطفل، فلن يحصل الطفل على الإدخال القياسي؛ هذا عادة ما تكون مشكلة. غير إغلاق std أقل أهمية.


إعادة النظر في التعليمات البرمجية المعدلة (اعتبارا من 2009-06-03T20: 52-07: 00) ...

افترض أن هذه العملية تبدأ في ملفات الملفات 0، 1، 2 (الإدخال القياسي والإخراج والخطأ) فتح فقط. افترض أيضا أن لدينا 3 أوامر بالضبط معالجتها. كما كان من قبل، يكتب هذا الرمز الحلقة الشراحية.

std0 = dup(0); // backup stdin - 3
std1 = dup(1); // backup stdout - 4

// Iteration 1 (i == 1)
// We have another command
pipe(fd);   // fd[0] = 5; fd[1] = 6
aux = fd[0]; // aux = 5
dup2(fd[1], 1);
close(fd[1]);       // 6 closed
// Not last command
if (fork() == 0) {
    // Not last command
    close(std1);    // 4 closed
    close(fd[0]);   // 5 closed
    // Minor problemette: 3 still open
    execlp(argv[i], argv[i], NULL);
    }
// Parent has open 3, 4, 5 - no problem

// Iteration 2 (i == 2)
// There was a previous command
dup2(aux, 0);      // stdin now on read end of pipe
close(aux);        // 5 closed
// We have another command
pipe(fd);          // fd[0] = 5; fd[1] = 6
aux = fd[0];
dup2(fd[1], 1);
close(fd[1]);      // 6 closed
// Not last command
if (fork() == 0) {
    // Not last command
    close(std1);   // 4 closed
    close(fd[0]);  // 5 closed
    // As before, 3 is still open - not a major problem
    execlp(argv[i], argv[i], NULL);
    }
// Parent has open 3, 4, 5 - no problem

// Iteration 3 (i == 3)
// We have a previous command
dup2(aux, 0);      // stdin is now read end of pipe 
close(aux);        // 5 closed
// No more commands

// Last command - restore stdout...
dup2(std1, 1);     // stdin is back where it started
close(std1);       // 4 closed

if (fork() == 0) {
    // Last command
    // 3 still open
    execlp(argv[i], argv[i], NULL);
}
// Parent has closed 4 when it should not have done so!!!
// End of loop
// restore stdin to be able to keep using the shell
dup2(std0, 0);
// 3 still open - as desired

لذلك، يتمتع جميع الأطفال بالإدخال القياسي الأصلي المتصل كاصف الملف 3. هذا ليس مثاليا، على الرغم من أنه ليس صدفا بشكل مخيف؛ أنا من الصعب الضغط للعثور على ظرف حيث هذا مهم.

إغلاق الملف واصف 4 في الوالد هو خطأ - التكرار التالي لقراءة الأمر ومعالجته لن يعمل std1 لا تتم تهيئتها داخل الحلقة.

بشكل عام، هذا قريب من الصحيح - ولكن ليس صحيحا تماما.

سيعطي النتائج، بعض غير متوقع. إنه أبعد ما يكون عن حل جميل: يفسد مع البيانات الأصلية "الواصفات القياسية"، لا يستعيد الإدخال القياسي، تسرب الواصفات إلى الأطفال، إلخ.

إذا كنت تعتقد بشكل متكرر، فقد يكون من الأسهل فهمه. أدناه هو الحل الصحيح، دون التحقق من الأخطاء. النظر في نوع قائمة مرتبط command, ، مع ل next مؤشر و argv مجموعة مصفوفة.

void run_pipeline(command *cmd, int input) {
  int pfds[2] = { -1, -1 };

  if (cmd->next != NULL) {
    pipe(pfds);
  }
  if (fork() == 0) { /* child */
    if (input != -1) {
      dup2(input, STDIN_FILENO);
      close(input);
    }
    if (pfds[1] != -1) {
      dup2(pfds[1], STDOUT_FILENO);
      close(pfds[1]);
    }
    if (pfds[0] != -1) {
      close(pfds[0]);
    }
    execvp(cmd->argv[0], cmd->argv);
    exit(1);
  }
  else { /* parent */
    if (input != -1) {
      close(input);
    }
    if (pfds[1] != -1) {
      close(pfds[1]);
    }
    if (cmd->next != NULL) {
      run_pipeline(cmd->next, pfds[0]);
    }
  }
}

اتصل به مع الأمر الأول في القائمة المرتبطة، و input = -1. يفعل الباقي.

سواء في هذا السؤال وفي آخر (كما يرتبط في أول وظيفة)، ephemient اقترح لي حل للمشكلة دون العبث مع واصفات ملف الوالدين كما يتضح من الحل المحتمل في هذا السؤال.

لم أحصل على حله، حاولت وحاولت أن أفهم لكنني لا يبدو لي أن أحصل عليه. لقد حاولت أيضا كودها دون فهم لكنها لم تنجح. ربما لأنني فشلت في فهمه بشكل صحيح ولم يكن قادرا على رمزه الذي كان يجب ترميزه.

على أي حال، حاولت التوصل إلى حل الخاص باستخدام بعض الأشياء التي فهمتها من الرمز الزائدي وتوصلت إلى هذا:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>

#define NUMPIPES 5
#define NUMARGS 10

int main(int argc, char *argv[]) {
    char *bBuffer, *sPtr, *aPtr = NULL, *pipeComms[NUMPIPES], *cmdArgs[NUMARGS];
    int aPipe[2], bPipe[2], pCount, aCount, i, status;
    pid_t pid;

    using_history();

    while(1) {
        bBuffer = readline("\e[1;31mShell \e[1;32m# \e[0m");

        if(!strcasecmp(bBuffer, "exit")) {
            return 0;
        }

        if(strlen(bBuffer) > 0) {
            add_history(bBuffer);
        }

        sPtr = bBuffer;
        pCount =0;

        do {
            aPtr = strsep(&sPtr, "|");

            if(aPtr != NULL) {
                if(strlen(aPtr) > 0) {
                    pipeComms[pCount++] = aPtr;
                }
            }
        } while(aPtr);

        cmdArgs[pCount] = NULL;

        for(i = 0; i < pCount; i++) {
            aCount = 0;

            do {
                aPtr = strsep(&pipeComms[i], " ");

                if(aPtr != NULL) {
                    if(strlen(aPtr) > 0) {
                        cmdArgs[aCount++] = aPtr;
                    }
                }
            } while(aPtr);

            cmdArgs[aCount] = NULL;

            // Do we have a next command?
            if(i < pCount-1) {
                // Is this the first, third, fifth, etc... command?
                if(i%2 == 0) {
                    pipe(aPipe);
                }

                // Is this the second, fourth, sixth, etc... command?
                if(i%2 == 1) {
                    pipe(bPipe);
                }
            }

            pid = fork();

            if(pid == 0) {
                // Is this the first, third, fifth, etc... command?
                if(i%2 == 0) {
                    // Do we have a previous command?
                    if(i > 0) {
                        close(bPipe[1]);
                        dup2(bPipe[0], STDIN_FILENO);
                        close(bPipe[0]);
                    }

                    // Do we have a next command?
                    if(i < pCount-1) {
                        close(aPipe[0]);
                        dup2(aPipe[1], STDOUT_FILENO);
                        close(aPipe[1]);
                    }
                }

                // Is this the second, fourth, sixth, etc... command?
                if(i%2 == 1) {
                    // Do we have a previous command?
                    if(i > 0) {
                        close(aPipe[1]);
                        dup2(aPipe[0], STDIN_FILENO);
                        close(aPipe[0]);
                    }

                    // Do we have a next command?
                    if(i < pCount-1) {
                        close(bPipe[0]);
                        dup2(bPipe[1], STDOUT_FILENO);
                        close(bPipe[1]);
                    }
                }

                execvp(cmdArgs[0], cmdArgs);
                exit(1);
            } else {
                // Do we have a previous command?
                if(i > 0) {
                    // Is this the first, third, fifth, etc... command?
                    if(i%2 == 0) {
                        close(bPipe[0]);
                        close(bPipe[1]);
                    }

                    // Is this the second, fourth, sixth, etc... command?
                    if(i%2 == 1) {
                        close(aPipe[0]);
                        close(aPipe[1]);
                    }
                }

                // wait for the last command? all others will run in the background
                if(i == pCount-1) {
                    waitpid(pid, &status, 0);
                }

                // I know they will be left as zombies in the table
                // Not relevant for this...
            }
        }
    }

    return 0;
}

قد لا يكون هذا أفضل ونظافة حلا، لكنه كان شيئا يمكنني التوصل إليه، والأهم من ذلك، شيء يمكنني فهمه. ما هو الخير هو أن يكون لديك شيء ما لا أفهمه ثم أنا تقييمه من قبل أستاذي ولا أستطيع أن أشرح له ما يفعله القانون؟

على أي حال، ما رأيك في هذا واحد؟

هذا هو رمز "النهائي" الخاص بي ephemient اقتراحات:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>

#define NUMPIPES 5
#define NUMARGS 10

int main(int argc, char *argv[]) {
    char *bBuffer, *sPtr, *aPtr = NULL, *pipeComms[NUMPIPES], *cmdArgs[NUMARGS];
    int newPipe[2], oldPipe[2], pCount, aCount, i, status;
    pid_t pid;

    using_history();

    while(1) {
        bBuffer = readline("\e[1;31mShell \e[1;32m# \e[0m");

        if(!strcasecmp(bBuffer, "exit")) {
            return 0;
        }

        if(strlen(bBuffer) > 0) {
            add_history(bBuffer);
        }

        sPtr = bBuffer;
        pCount = -1;

        do {
            aPtr = strsep(&sPtr, "|");

            if(aPtr != NULL) {
                if(strlen(aPtr) > 0) {
                    pipeComms[++pCount] = aPtr;
                }
            }
        } while(aPtr);

        cmdArgs[++pCount] = NULL;

        for(i = 0; i < pCount; i++) {
            aCount = -1;

            do {
                aPtr = strsep(&pipeComms[i], " ");

                if(aPtr != NULL) {
                    if(strlen(aPtr) > 0) {
                        cmdArgs[++aCount] = aPtr;
                    }
                }
            } while(aPtr);

            cmdArgs[++aCount] = NULL;

            // do we have a next command?
            if(i < pCount-1) {
                pipe(newPipe);
            }

            pid = fork();

            if(pid == 0) {
                // do we have a previous command?
                if(i > 0) {
                    close(oldPipe[1]);
                    dup2(oldPipe[0], 0);
                    close(oldPipe[0]);
                }

                // do we have a next command?
                if(i < pCount-1) {
                    close(newPipe[0]);
                    dup2(newPipe[1], 1);
                    close(newPipe[1]);
                }

                // execute command...
                execvp(cmdArgs[0], cmdArgs);
                exit(1);
            } else {
                // do we have a previous command?
                if(i > 0) {
                    close(oldPipe[0]);
                    close(oldPipe[1]);
                }

                // do we have a next command?
                if(i < pCount-1) {
                    oldPipe[0] = newPipe[0];
                    oldPipe[1] = newPipe[1];
                }

                // wait for last command process?
                if(i == pCount-1) {
                    waitpid(pid, &status, 0);
                }
            }
        }
    }

    return 0;
}

هل هو موافق الآن؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top