执行一个命令行管道下与叉()和exec() [英] Executing a command-line pipeline in C with fork() and exec()

查看:197
本文介绍了执行一个命令行管道下与叉()和exec()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问了一下我的code和得到的答复是,这是不正确。
PERROR在这种情况下使用
现在我不知道我怎么能调整和完善,使我将不再有这些错误?


  

execvp不返回,除非发生错误,因此,如果所有的作品,
  封闭功能将不会再回来。


  
  

值i是已经过去的数组中,由于CMD结束
  前循环,所以CMD [I] .argv [0]是不正确的。


  
  

cmd是不是数组结构的命令,所以不应该被索引


  
  

在cmd.argv的第一项是一个指针阵列,其中最后一个
  条目是NULL。在execvp将这项工作(且只有)阵列等等
  其他所有指向数组的指针将被忽略


  
  

有大量的code错误。例如,该
  第一次通过的fork_pipe()循环包含垃圾。该
  传递给execvp()的第二个参数需要是一个指向字符
  串,以最终NULL指针。这最后的NULL指针
  缺失,有很多问题比较多。


 的#include< SYS / types.h中>
#包括LT&;&errno.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&unistd.h中GT;
#包括LT&;&string.h中GT;
结构命令
{
    为const char ** argv的;
};
/ *辅助函数,产生进程* /
INT spawn_proc(int类型,int的列,结构命令* CMD){
    将为pid_t PID;
    如果((PID =叉())== 0){
        如果(在!= 0){
            / *如果(dup2(在0)== -1){
                PERROR(dup2失败);
                出口(1);
            } * /
            dup2(在0);
            逼近);
        }
        如果(满分!= 1){
            dup2(出,1);
            关闭(出);
        }
        如果(execvp(CMD->的argv [0],(char * const的*)CMD->的argv)小于0){
            PERROR(execvp失败);
            出口(1);
        }
    }否则如果(PID℃,){
        PERROR(叉失败);
        出口(1);
    }
    返回PID;
}
/ *辅助函数叉管* /
INT fork_pipes(INT N,结构命令* CMD){
    INT I;
    int类型,FD [2];
    对于(i = 0; I< N - 1 ++ I){
        管(FD);
        spawn_proc(中,FD [1],CMD + I);
        关闭(FD [1]);
        在= FD [0];
    }
    dup2(在0);
    / *返回execvp(CMD [I] .argv [0],(char * const的*)CMD [I] .argv); * /
    如果(execvp(CMD [I] .argv [0],(char * const的*)CMD [I] .argv)小于0){
        PERROR(execvp失败);
        出口(1);
    }其他{
        返回execvp(CMD [I] .argv [0],(char * const的*)CMD [I] .argv);
    }
}INT主(INT ARGC,字符** argv的){
    INT I;
    如果(ARGC == 1){/ *有没有参数* /
        为const char * printenv [] = {printenv,0};
        为const char *排序[] = {排序,0};
        为const char *更少[] = {少,0};
        结构命令CMD [] = {{printenv},{排序},{少}};
        返回fork_pipes(3,CMD);
    }
    如果(ARGC大于1){/ *我想一个参数* /        如果(STRNCMP(的argv [1],CD,2)及和放大器; STRNCMP(的argv [1],退出,2)){
            字符* tmp目录;
            INT LEN = 1;
            对于(i = 1; I< ARGC,我++)
            {
                LEN + = strlen的(的argv [I])+ 2;
            }
            TMP =(字符*)malloc的(LEN);
            TMP [0] ='\\ 0';
            INT POS = 0;
            对于(i = 1; I< ARGC,我++)
            {
                POS + = sprintf的(TMP + POS,%s%S(我== 1:?|)的argv [I]);
            }
            为const char * printenv [] = {printenv,0};
            为const char *的grep [] = {grep的,-E,TMP,NULL};
            为const char *排序[] = {排序,0};
            为const char *更少[] = {少,0};
            结构命令CMD [] = {{printenv},{grep的},{排序},{少}};
            返回fork_pipes(4,CMD);
            免费(TMP);
        }否则如果(!STRNCMP(的argv [1],CD,2)){/ *更改目录* /
            的printf(更改目录到%s \\ n,argv的[2]);
            CHDIR(的argv [2]);
        }否则如果(!STRNCMP(的argv [1],退出,2)){/ *更改目录* /
            的printf(退出\\ n);
            出口(0);
        }
    }
    出口(0);
}


解决方案

传输到意见(部分)的答案。


  • 您不需要在 execvp()(如果它返回时,它将失败)的测试,但你需要的错误报告并退出调用后吧。


  • CMD 不是数组的评论似乎是伪造的; fork_pipes内(),它是一个数组。它不是用来作为内部数组spawn_proc()


  • 我觉得评论在 cmd.argv 的第一项是一个指针数组,其中最后一项为NULL。在 execvp 的(并且只有)阵列,因此所有其他的指向数组的指针会被忽略上的工作是假的了。我认为他们忽视的是,你要创建的结构命令的数组。


  • 我觉得评论'的值 I 已经是过去的数组中的 CMD 结束由于现有循环,所以 CMD [I] .argv [0] 是不正确的不正确,因为循环为(i = 0 ; I< N - 1;我++)所以 I N-1 之后循环,数组 CMD 有元素 0到n-1 来解决。


  • 然而,在第一次调用 spawn_proc值()确实是垃圾。也许你可以简单地将其设置为 0 STDIN_FILENO ),并行,但你需要验证。但关于第二个参数 execvp()的评论是奇特 - 中投应该缺席,但除此之外,code看起来不错给我。我要补充一点,我还没有运行编译过任何这一点,所以任何事情到目前为止,我已经说过要站在由编译器进行修正。但我不这样做的分析随便要么...你跟你的编译器编译设置挑剔:的gcc -Wall -Wextra -Werror 作为最低(我用的更多的选择!)


  • fork_pipes(),在 execvp的如果测试() 其他子句是怪异。你只需要 execvp)电话() PERROR()退出(



上述立场基本准确这些意见。下面是一些修改code,但修改大多是化妆品。在 err_syserr()功能是基于什么我用报告错误。这是一个可变参数的函数,还报告了系统错误。它比 PERROR(),因为(a),它可以格式化多个COM prehensively及(b)将退出。

更好

我正在编译警告,如:

  ft13.c:在函数'spawn_proc:
ft13.c:45:9:错误:从兼容的指针类型传递execvp的论点2 [-Werror]
         execvp(CMD->的argv [0],CMD->的argv);
         ^
6:0文件从ft13.c包括:
/usr/include/unistd.h:440:6:注:应为char * const的*',但参数的类型为为const char **'
 INT execvp(为const char *,char * const的*);

要解决这些最简单的方法是将常量在正确的位置在结构命令并消除在常量从各种命令的参数列表。

其他的变化比真正的实质性的(在未初始化的是唯一严重的错误修复)更多化妆品。我已经用我的错误报告code,并检查了一些额外的系统调用(即 dup2()的人,例如),并清理了 execvp()和错误报告。我搬到了退出和测试 CD 进取一般code,以避免重复测试。此外,您使用 STRNCMP()和测试退出只是看着,但是一个系统命令使用的strcmp()。我使用 STRCMP(X,Y)== 0 中的条件;在使用中模仿关系运算符关系操作我测试(所以 STRCMP(X,Y)> = 0 测试 X 大于或等于,等等)。

现代POSIX不需要的#include< SYS / types.h中> 为包括。其他的头把它作为必要的。

来源: ft13.c

编译到 FT13

 的#include<&errno.h中GT;
#包括LT&;&STDARG.H GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;
#包括LT&;&unistd.h中GT;结构命令
{
    char * const的* argv的;
};静态_Noreturn无效err_syserr(字符* FMT,...)
{
    INT的差错编号= errno的;
    va_list的ARGS;
    的va_start(参数,FMT);
    vfprintf(标准错误,格式化,参数);
    va_end用来(参数);
    如果(差错编号!= 0)
        fprintf中(标准错误,(%D:%S)\\ n,差错编号,字符串错误(差错编号));
    出口(EXIT_FAILURE);
}/ *辅助函数,产生进程* /
静态INT spawn_proc(int类型,int的列,结构命令* CMD)
{
    将为pid_t PID;
    如果((PID =叉())== 0)
    {
        如果(在!= 0)
        {
            如果(dup2(在0)小于0)
                err_syserr(dup2()的标准输入失败%S:CMD->的argv [0]);
            逼近);
        }
        如果(满分!= 1)
        {
            如果(dup2(出,1)℃下)
                err_syserr(dup2()在stdout失败%S:CMD->的argv [0]);
            关闭(出);
        }
        fprintf中(标准错误,%D:执行%S \\ n,(INT)GETPID(),CMD->的argv [0]);
        execvp(CMD->的argv [0],CMD->的argv);
        err_syserr(无法执行%S:CMD->的argv [0]);
    }
    否则如果(PID℃,)
        err_syserr(叉失败:);
    返回PID;
}/ *辅助函数叉管* /
静态无效fork_pipes(INT N,结构命令* CMD)
{
    INT I;
    int类型= 0;
    INT FD [2];
    对于(i = 0; I< N - 1 ++ I)
    {
        管(FD);
        spawn_proc(中,FD [1],CMD + I);
        关闭(FD [1]);
        在= FD [0];
    }
    如果(dup2(在0)小于0)
        err_syserr(dup2()失败的标准输入%s的:CMD [I] .argv [0]);
    fprintf中(标准错误,%D:执行%S \\ n,(INT)GETPID(),CMD [I] .argv [0]);
    execvp(CMD [I] .argv [0],CMD [I] .argv);
    err_syserr(无法执行%S:CMD [I] .argv [0]);
}INT主(INT ARGC,字符** argv的)
{
    INT I;
    如果(ARGC == 1)/ *有没有参数* /
    {
        字符* printenv [] = {printenv,0};
        字符*排序[] = {排序,0};
        字符*更少[] = {少,0};
        结构命令CMD [] = {{printenv},{排序},{少}};
        fork_pipes(3,CMD);
    }
    其他
    {
        如果(STRCMP(的argv [1],CD)== 0)/ *更改目录* /
        {
            的printf(更改目录到%s \\ n,argv的[2]);
            CHDIR(的argv [2]);
        }
        否则,如果(STRCMP(的argv [1],退出)== 0)
        {
            的printf(退出\\ n);
            出口(0);
        }
        其他
        {
            字符* tmp目录;
            INT LEN = 1;
            对于(i = 1; I< ARGC,我++)
            {
                LEN + = strlen的(的argv [I])+ 2;
            }
            TMP =(字符*)malloc的(LEN);
            TMP [0] ='\\ 0';
            INT POS = 0;
            对于(i = 1; I< ARGC,我++)
            {
                POS + = sprintf的(TMP + POS,%s%S(我== 1:?|)的argv [I]);
            }
            字符* printenv [] = {printenv,0};
            的char *的grep [] = {grep的,-E,TMP,NULL};
            字符*排序[] = {排序,0};
            字符*更少[] = {少,0};
            结构命令CMD [] = {{printenv},{grep的},{排序},{少}};
            fork_pipes(4,CMD);
            免费(TMP);
        }
    }
    返回(0);
}

示例运行

示例1:

  $ ./ft13 |猫
1733:执行少
1735年:在执行printenv
1736:在执行排序
Apple_PubSub_Socket_Render = /私有的/ tmp / com.apple.launchd.sl7NmyZPgI /渲染
BASH_ENV = /用户/ jleffler / .bashrc中
CDPATH=:/Users/jleffler:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work:/Users/jleffler/ids
CLICOLOR = 1
......很多环境省略...
VISUAL = VIM
XPC_FLAGS =为0x0
XPC_SERVICE_NAME = 0
_ = / FT13
__CF_USER_TEXT_ENCODING = 0x1F7:为0x0:为0x0
$

示例2:

  $ PATH ./ft13 |猫
1739:执行printenv
1737:执行少
1740:在执行的grep
1741:在执行排序
CDPATH=:/Users/jleffler:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work:/Users/jleffler/ids
DYLD_LIBRARY_PATH=/usr/lib:/usr/informix/11.70.FC6/lib:/usr/informix/11.70.FC6/lib/esql:/usr/informix/11.70.FC6/lib/cli
GOPATH = /用户/ jleffler /软件/去-1.2
LD_LIBRARY_PATH = / usr / lib目录:在/ usr / GNU / lib目录下:/usr/g​​cc/v4.9.1/lib
MANPATH=/Users/jleffler/man:/Users/jleffler/share/man:/usr/local/mysql/man:/usr/gcc/v4.9.1/share/man:/Users/jleffler/perl/v5.20.1/man:/usr/local/man:/usr/local/share/man:/opt/local/man:/opt/local/share/man:/usr/share/man:/usr/gnu/man:/usr/gnu/share/man
PATH=/Users/jleffler/bin:/usr/informix/11.70.FC6/bin:.:/usr/local/mysql/bin:/usr/gcc/v4.9.1/bin:/Users/jleffler/perl/v5.20.1/bin:/usr/local/go/bin:/Users/jleffler/Software/go-1.2/bin:/usr/local/bin:/opt/local/bin:/usr/bin:/bin:/usr/gnu/bin:/usr/sbin:/sbin
$

I asked about my code and the answer was that it is incorrect. perror usage in this case Now I wonder how I can adjust and improve so that I no longer will have these errors?

execvp does not return, except if an error occurs, so if all works, the enclosing function will never return.

the value 'i' is already past the end of the array in 'cmd' due to the prior loop, so 'cmd[i].argv[0] is not correct.

cmd is not an array, of struct command, so should not be indexed

the first entry in cmd.argv is a pointer to an array where the last entry is NULL. the execvp will work on that (and only that) array so all other pointers to arrays will be ignored

There are a large number of errors in the code. for instance, the first time through the loop in fork_pipe() 'in' contains garbage. the second parameter passed to execvp() needs to be a pointer to character strings, with a final NULL pointer. That final NULL pointer is missing, There are plenty more problems

#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
struct command
{
    const char **argv;
};
/* Helper function that spawns processes */
int spawn_proc (int in, int out, struct command *cmd) {
    pid_t pid;
    if ((pid = fork ()) == 0) {
        if (in != 0) {
            /*if (dup2(in, 0) == -1) {
                perror("dup2 failed");
                exit(1);
            }*/
            dup2 (in, 0);
            close (in);
        }
        if (out != 1) {
            dup2 (out, 1);
            close (out);
        }
        if (execvp(cmd->argv [0], (char * const *)cmd->argv) < 0) {
            perror("execvp failed");
            exit(1);
        }
    } else if (pid < 0) {
        perror("fork failed");
        exit(1);
    }
    return pid;
}
/* Helper function that forks pipes */
int fork_pipes (int n, struct command *cmd) {
    int i;
    int in, fd [2];
    for (i = 0; i < n - 1; ++i) {
        pipe (fd);
        spawn_proc (in, fd [1], cmd + i);
        close (fd [1]);
        in = fd [0];
    }
    dup2 (in, 0);
    /*return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);*/
    if (execvp (cmd [i].argv [0], (char * const *)cmd [i].argv) < 0) {
        perror("execvp failed");
        exit(1);
    } else {
        return execvp (cmd [i].argv [0], (char * const *)cmd [i].argv);
    }
}

int main (int argc, char ** argv) {
    int i;
    if (argc == 1) { /* There were no arguments */
        const char *printenv[] = { "printenv", 0};
        const char *sort[] = { "sort", 0 };
        const char *less[] = { "less", 0 };
        struct command cmd [] = { {printenv}, {sort}, {less} };
        return fork_pipes (3, cmd);
    }
    if (argc > 1) { /* I'd like an argument */

        if (strncmp(argv[1], "cd", 2) && strncmp(argv[1], "exit", 2)) {
            char *tmp;
            int len = 1;
            for( i=1; i<argc; i++)
            {
                len += strlen(argv[i]) + 2;
            }
            tmp = (char*) malloc(len);
            tmp[0] = '\0';
            int pos = 0;
            for( i=1; i<argc; i++)
            {
                pos += sprintf(tmp+pos, "%s%s", (i==1?"":"|"), argv[i]);
            }
            const char *printenv[] = { "printenv", 0};
            const char *grep[] = { "grep", "-E", tmp, NULL};
            const char *sort[] = { "sort", 0 };
            const char *less[] = { "less", 0 };
            struct command cmd [] = { {printenv}, {grep}, {sort}, {less} };
            return fork_pipes (4, cmd);
            free(tmp);
        } else if (! strncmp(argv[1], "cd", 2)) { /* change directory */
            printf("change directory to %s\n" , argv[2]);
            chdir(argv[2]);
        } else if (! strncmp(argv[1], "exit", 2)) { /* change directory */
            printf("exit\n");
            exit(0);
        }
    }
    exit(0);
}

解决方案

Transferring comments into (part of) an answer.

  • You don't need the test on execvp() (if it returns, it failed), but you do need the error reporting and exit call after it.

  • The 'cmd is not an array' comment seems to be bogus; inside fork_pipes(), it is an array. It is not used as an array inside spawn_proc().

  • I think the comment 'The first entry in cmd.argv is a pointer to an array where the last entry is NULL. The execvp will work on that (and only that) array so all other pointers to arrays will be ignored' is bogus too. I think they overlooked that you're creating an array of struct command's.

  • I think the comment 'the value i is already past the end of the array in cmd due to the prior loop, so cmd[i].argv[0] is not correct' is incorrect because the loop is for (i = 0; i < n - 1; i++) so i is n-1 after the loop, and the array cmd has elements 0..n-1 to address.

  • However, the value of in in the first call to spawn_proc() is indeed garbage. Probably you can simply set it to 0 (STDIN_FILENO) and be OK, but you need to verify that. But the comment about the second argument to execvp() is peculiar — the cast should be absent, but otherwise the code looks OK to me. I should add that I've not yet run a compiler over any of this, so anything I've said so far stands to be corrected by a compiler. But I'm not doing the analysis casually either… Are you compiling with your compiler set fussy: gcc -Wall -Wextra -Werror as a minimum (I use more options!)?

  • In fork_pipes(), the if test on execvp() and the else clause are weird. You just need calls to execvp(), perror() and exit().


These comments above stand basically accurate. Here is some modified code, but the modifications are mostly cosmetic. The err_syserr() function is based on what I use for reporting errors. It is a varargs function that also reports the system error. It is better than perror() because (a) it can format more comprehensively and (b) it exits.

I was getting compilation warnings like:

ft13.c: In function ‘spawn_proc’:
ft13.c:45:9: error: passing argument 2 of ‘execvp’ from incompatible pointer type [-Werror]
         execvp(cmd->argv[0], cmd->argv);
         ^
In file included from ft13.c:6:0:
/usr/include/unistd.h:440:6: note: expected ‘char * const*’ but argument is of type ‘const char **’
 int  execvp(const char *, char * const *);

The easiest way to fix these is to place the const in the correct place in struct command and to remove the const from the argument lists for the various commands.

Other changes are more cosmetic than really substantive (the uninitialized in was the only serious bug to fix). I've use my error reporting code, and checked some extra system calls (the dup2() ones, for example), and cleaned up the execvp() and error reporting. I moved the tests for exit and cd ahead of the general code to avoid repeating the tests. Also, you were using strncmp() and the test for exit was only looking at ex, but ex is a system command… Use strcmp(). I use strcmp(x, y) == 0 in the condition; the relational operator in use mimics the relational operation I'm testing (so strcmp(x, y) >= 0 tests for x greater than or equal to y, etc.).

Modern POSIX does not require #include <sys/types.h> as an include. The other headers include it as necessary.

Source: ft13.c

Compiled to ft13.

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

struct command
{
    char * const *argv;
};

static _Noreturn void err_syserr(char *fmt, ...)
{
    int errnum = errno;
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    if (errnum != 0)
        fprintf(stderr, "(%d: %s)\n", errnum, strerror(errnum));
    exit(EXIT_FAILURE);
}

/* Helper function that spawns processes */
static int spawn_proc(int in, int out, struct command *cmd)
{
    pid_t pid;
    if ((pid = fork()) == 0)
    {
        if (in != 0)
        {
            if (dup2(in, 0) < 0)
                err_syserr("dup2() failed on stdin for %s: ", cmd->argv[0]);
            close(in);
        }
        if (out != 1)
        {
            if (dup2(out, 1) < 0)
                err_syserr("dup2() failed on stdout for %s: ", cmd->argv[0]);
            close(out);
        }
        fprintf(stderr, "%d: executing %s\n", (int)getpid(), cmd->argv[0]);
        execvp(cmd->argv[0], cmd->argv);
        err_syserr("failed to execute %s: ", cmd->argv[0]);
    }
    else if (pid < 0)
        err_syserr("fork failed: ");
    return pid;
}

/* Helper function that forks pipes */
static void fork_pipes(int n, struct command *cmd)
{
    int i;
    int in = 0;
    int fd[2];
    for (i = 0; i < n - 1; ++i)
    {
        pipe(fd);
        spawn_proc(in, fd[1], cmd + i);
        close(fd[1]);
        in = fd[0];
    }
    if (dup2(in, 0) < 0)
        err_syserr("dup2() failed on stdin for %s: ", cmd[i].argv[0]);
    fprintf(stderr, "%d: executing %s\n", (int)getpid(), cmd[i].argv[0]);
    execvp(cmd[i].argv[0], cmd[i].argv);
    err_syserr("failed to execute %s: ", cmd[i].argv[0]);
}

int main(int argc, char **argv)
{
    int i;
    if (argc == 1)   /* There were no arguments */
    {
        char *printenv[] = { "printenv", 0};
        char *sort[] = { "sort", 0 };
        char *less[] = { "less", 0 };
        struct command cmd[] = { {printenv}, {sort}, {less} };
        fork_pipes(3, cmd);
    }
    else
    {
        if (strcmp(argv[1], "cd") == 0)      /* change directory */
        {
            printf("change directory to %s\n", argv[2]);
            chdir(argv[2]);
        }
        else if (strcmp(argv[1], "exit") == 0)
        {
            printf("exit\n");
            exit(0);
        }
        else
        {
            char *tmp;
            int len = 1;
            for (i = 1; i < argc; i++)
            {
                len += strlen(argv[i]) + 2;
            }
            tmp = (char *) malloc(len);
            tmp[0] = '\0';
            int pos = 0;
            for (i = 1; i < argc; i++)
            {
                pos += sprintf(tmp + pos, "%s%s", (i == 1 ? "" : "|"), argv[i]);
            }
            char *printenv[] = { "printenv", 0};
            char *grep[] = { "grep", "-E", tmp, NULL};
            char *sort[] = { "sort", 0 };
            char *less[] = { "less", 0 };
            struct command cmd[] = { {printenv}, {grep}, {sort}, {less} };
            fork_pipes(4, cmd);
            free(tmp);
        }
    }
    return(0);
}

Example runs

Sample 1:

$ ./ft13 | cat
1733: executing less
1735: executing printenv
1736: executing sort
Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.sl7NmyZPgI/Render
BASH_ENV=/Users/jleffler/.bashrc
CDPATH=:/Users/jleffler:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work:/Users/jleffler/ids
CLICOLOR=1
…lots of environment omitted…
VISUAL=vim
XPC_FLAGS=0x0
XPC_SERVICE_NAME=0
_=./ft13
__CF_USER_TEXT_ENCODING=0x1F7:0x0:0x0
$

Sample 2:

$ ./ft13 PATH | cat
1739: executing printenv
1737: executing less
1740: executing grep
1741: executing sort
CDPATH=:/Users/jleffler:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work:/Users/jleffler/ids
DYLD_LIBRARY_PATH=/usr/lib:/usr/informix/11.70.FC6/lib:/usr/informix/11.70.FC6/lib/esql:/usr/informix/11.70.FC6/lib/cli
GOPATH=/Users/jleffler/Software/go-1.2
LD_LIBRARY_PATH=/usr/lib:/usr/gnu/lib:/usr/gcc/v4.9.1/lib
MANPATH=/Users/jleffler/man:/Users/jleffler/share/man:/usr/local/mysql/man:/usr/gcc/v4.9.1/share/man:/Users/jleffler/perl/v5.20.1/man:/usr/local/man:/usr/local/share/man:/opt/local/man:/opt/local/share/man:/usr/share/man:/usr/gnu/man:/usr/gnu/share/man
PATH=/Users/jleffler/bin:/usr/informix/11.70.FC6/bin:.:/usr/local/mysql/bin:/usr/gcc/v4.9.1/bin:/Users/jleffler/perl/v5.20.1/bin:/usr/local/go/bin:/Users/jleffler/Software/go-1.2/bin:/usr/local/bin:/opt/local/bin:/usr/bin:/bin:/usr/gnu/bin:/usr/sbin:/sbin
$

这篇关于执行一个命令行管道下与叉()和exec()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆