写入错误:使用execlp在C中断开管道
我在创建从命令行获取参数的简单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 #
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函数的使用。请参阅下面的答案。