Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
写入错误:使用execlp在C中断开管道_C_Unix - Fatal编程技术网

写入错误:使用execlp在C中断开管道

写入错误:使用execlp在C中断开管道,c,unix,C,Unix,我在创建从命令行获取参数的简单C程序时遇到问题,最后一个参数是文件的路径。程序对给定文件运行cat命令,然后对cat的结果运行tr。Tr从命令行获取参数(不是最后一个参数)。我发现了一些错误: 缺少操作数。 写入错误:管道破裂。 我不确定错误在哪里 #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define WRITE_END 1 #

我在创建从命令行获取参数的简单C程序时遇到问题,最后一个参数是文件的路径。程序对给定文件运行
cat
命令,然后对cat的结果运行tr。Tr从命令行获取参数(不是最后一个参数)。我发现了一些错误: 缺少操作数。 写入错误:管道破裂。 我不确定错误在哪里

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

#define WRITE_END 1
#define READ_END 0

int main(int argc, char* argv[]){
    if(argc < 2){
        printf("\nPROVIDE AN ARGUMENT\n");
        return 1;
    }
    const char * file = argv[argc - 1];
    char ** args = calloc(argc - 2, sizeof(char*));
    for( int i = 1; i<argc-2; i++){
        args[i - 1 ] = argv[i];
    }

    int fd[2];
    pipe(fd);
    pid_t child;

    if((child = fork()) == -1)return 2;

    if(child == 0){
        dup2(fd[WRITE_END], STDOUT_FILENO);
        close(fd[READ_END]);
        close(fd[WRITE_END]);
        execlp("cat", "cat", file, (char*)NULL);
        exit(1);
    }
    else{
        dup2(fd[READ_END], STDIN_FILENO);
        close(fd[WRITE_END]);
        close(fd[READ_END]);
        execlp("tr", "tr", *args, (char*)NULL);
        exit(1);
    }

    close(fd[0]);
    close(fd[1]);
    wait(0);
    wait(0);

    return 0;
}
#包括
#包括
#包括
#包括
#定义WRITE_END 1
#定义读取结束0
int main(int argc,char*argv[]){
如果(argc<2){
printf(“\n提供参数\n”);
返回1;
}
const char*file=argv[argc-1];
char**args=calloc(argc-2,sizeof(char*);

对于(int i=1;i这里有一些问题阻碍了这项工作的进行。首先,正如Nate Eldredge在一篇评论中提到的,除了最后一个参数外,所有参数在分配和复制到变量
args
时都存在问题。其次,使用execlp有一个小问题,因为这些参数应该包含一个e与程序运行名称相对应的xtra参数(与作为可执行文件打开的文件不同,很多人对此感到困惑)。第三,正如Nate所提到的,您需要在与父进程相对应的if-else分支(“else”分支)中调用execvp。它的第二个参数需要是指向字符的指针数组,最后一个是
NULL

因此,一次只取一个。首先,您需要为
args
分配
argc
插槽,以便以您想要的方式使用它:

char ** args = calloc(argc, sizeof(char*));
memcpy(args, argv, sizeof(char*)*(argc -1));
第一行分配与arg.list大小相同的字符指针数组。第二行将
argv
中除最后一个指针外的所有指针复制到
args
中的相应位置,并将最后一个指针保留为
NULL
calloc
将存储初始化为零,如果要将
args
中的最后一个指针传递给execvp,则需要将其设为空指针。请注意,您不会复制argv下的所有存储,只复制第一维中的指针(请记住:
argv[0]
是指针,
argv[0][0]
是程序名中的第一个字符)

请注意,您使用的
close
dup
很好。我不知道为什么会有人反对这样做,除非他们忘记了分配文件描述符总是使用未使用的编号最低的描述符。这是UNIX中最初使用的描述符表最重要的一点

接下来,对
execlp
的调用(该调用将
fork
创建的子进程覆盖为“cat”)缺少一个参数。它应该是:

execlp("cat", "cat", file, (char*)NULL);
其中额外的
“cat”
是cat作为argv[0]输入
main()
时将收到的值。您可能会注意到,这看起来像是您可能会对正在使用exec函数运行的程序的名称撒谎,而且您可以(但不能完全隐藏已完成的操作)

最后是第二个execlp调用。您不能像在命令行中键入参数一样以一个大字符串传递参数:任何形式的exec都不会使用shell调用另一个程序,它也不会为您解析命令行。此外,您的方式(显然,如果我正确理解了您的意图的话)尝试连接参数字符串也不正确(请参阅上面关于
args
分配和
memcpy
调用的注释)因此,如果您有一个指向字符的指针数组,并且最后一个是
NULL
,就像在
args
中一样,在我指定的分配和复制数据的更改之后,您可以将
args
传递给
execvp

execvp("tr", args);
这些并不是很大的错误,很多人在开始操作参数列表和使用fork和exec函数时都会犯这样的错误。很多人在尝试在父进程和子进程之间使用管道时都会犯错误,但这一部分似乎是对的


最后一件事:只有在用新程序实际替换正在运行的程序时出现错误时,才会执行exec__u;调用的下游执行行。命令行“cat”或“tr”上出现错误,例如,不会导致exec___;失败。缺少执行作为第一个参数给定的文件的权限或缺少该文件等错误将导致exec____;函数失败。除非exec返回错误,否则在执行exec调用的过程中不会执行exec调用的下游内容(成功的exec永远不会返回).

dup(fd[0])
这并不是你想象的那样。你可能想研究
人dup2
,你的
args
变量是乱七八糟的;你实际上是在把
char*
数组复制到
char
数组中。当你真正想要的是
execlp
时,这似乎是一种误导性的尝试vp
。现在看来,如果(child==0){dup2(fd[WRITE_END],STDOUT_FILENO);close(fd[READ_END]);close(fd[WRITE_END]);execlp(“cat”,“cat”,file,(char*)NULL);exit(1)}否则{dup2(STDIN_FILENO,fd[READ_END]);close(fd[WRITE_END]);close(fd[READ_END]);execlp(“tr”,“tr”,“args,(char*)NULL);exit(1);}我认为管道仍然存在一些问题。这对我来说是一个非常模糊的话题:((在注释中阅读代码非常困难。请编辑您的问题以包含新版本。您处理管道的方式没有问题。问题在于args的分配和复制以及exec函数的使用。请参阅下面的答案。