Unix中dup2和管道代码中重定向输出的困难
我是unix新手。在下面的代码中,我从命令行“~$foo last sort more”传递三个参数以复制“~$last | sort | more”。我试图创建一个程序,将采取三个参数(至少目前3)。父进程将分叉三个进程。第一个进程将写入管道。第二个进程将读写管道,第三个进程将读写管道(终端)。第一个进程将执行“last”,第二个进程将执行“sort”,第三个进程将执行“more”,为了同步,这些进程将休眠1、2和3秒。我很确定我在创建管道和重定向输入输出时遇到了问题。我没有得到任何输出到终端,但我可以看到进程已经创建。我希望能得到一些帮助Unix中dup2和管道代码中重定向输出的困难,unix,exec,fork,pipe,dup2,Unix,Exec,Fork,Pipe,Dup2,我是unix新手。在下面的代码中,我从命令行“~$foo last sort more”传递三个参数以复制“~$last | sort | more”。我试图创建一个程序,将采取三个参数(至少目前3)。父进程将分叉三个进程。第一个进程将写入管道。第二个进程将读写管道,第三个进程将读写管道(终端)。第一个进程将执行“last”,第二个进程将执行“sort”,第三个进程将执行“more”,为了同步,这些进程将休眠1、2和3秒。我很确定我在创建管道和重定向输入输出时遇到了问题。我没有得到任何输出到终端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#define FOUND 1
#define NOT_FOUND 0
#define FIRST_CHILD 1
#define LAST_CHILD numargc
#define PATH_1 "/usr/bin/"
#define PATH_2 "/bin/"
#define DUP_READ() \
if (dup2(fdes[READ], fileno(stdin)) == -1) \
{ \
perror("dup error"); \
exit(4); \
}
#define DUP_WRITE() \
if (dup2(fdes[WRITE], fileno(stdout)) == -1) \
{ \
perror("dup error"); \
exit(4); \
}
#define CLOSE_FDES_READ() \
close(fdes[READ]);
#define CLOSE_FDES_WRITE() \
close(fdes[WRITE]);
#define EXEC(x, y) \
if (execl(arraycmds[x], argv[y], (char*)NULL) == -1) \
{ \
perror("EXEC ERROR"); \
exit(5); \
}
#define PRINT \
printf("FD IN:%d\n", fileno(stdin)); \
printf("FD OUT:%d\n", fileno(stdout));
enum
{
READ, /* 0 */
WRITE,
MAX
};
int cmdfinder( char* cmd, char* path); /* 1 -> found, 0 -> not found */
int main (int argc, char* argv[])
{
int numargc=argc-1;
char arraycmds[numargc][150];
int i=1, m=0, sleeptimes=5, numfork;
int rc=NOT_FOUND;
pid_t pid;
int fdes[2];
if(pipe(fdes) == -1)
{
perror("PIPE ERROR");
exit(4);
}
while(i <= numargc)
{
memset(arraycmds[m], 0, 150);
rc=cmdfinder(argv[i], arraycmds[m]);
if (rc)
{
printf("Command found:%s\n", arraycmds[m]);
}
i++;
m++;
}
i=0; //array index
numfork=1; //fork number
while(numfork <= numargc)
{
if ((pid=fork()) == -1)
{
perror("FORK ERROR");
exit(3);
}
else if (pid == 0)
{
/* Child */
sleep(sleeptimes);
if (numfork == FIRST_CHILD)
{
DUP_WRITE();
EXEC(i, numfork);
}
else if (numfork == LAST_CHILD)
{
DUP_READ();
CLOSE_FDES_WRITE();
EXEC(i, numfork);
}
else
{
DUP_READ();
DUP_WRITE();
CLOSE_FDES_READ();
CLOSE_FDES_WRITE();
EXEC(i, numfork);
}
}
else
{
/* Parent */
printf("pid:%d\n", pid);
i++;
numfork++;
sleeptimes++;
}
}
PRINT;
printf("i:%d\n", i);
printf("numfork:%d\n", numfork);
printf("DONE\n");
return 0;
}
int cmdfinder(char* cmd, char* path)
{
DIR* dir;
struct dirent *direntry;
char *pathdir;
int searchtimes=2;
while (searchtimes)
{
pathdir = (char*)malloc(250);
memset(pathdir, 0, 250);
if (searchtimes==2)
{
pathdir=PATH_1;
}
else
{
pathdir=PATH_2;
}
if ((dir = opendir(pathdir)) == NULL)
{
perror("Directory not found");
exit (1);
}
else
{
while (direntry = readdir(dir))
{
if (strncmp( direntry->d_name, cmd, strlen(cmd)) == 0)
{
strcat(path, pathdir);
strcat(path, cmd);
//searchtimes--;
return FOUND;
}
}
}
closedir(dir);
searchtimes--;
}
printf("%s: Not Found\n", cmd);
return NOT_FOUND;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义找到的1
#未找到定义\u 0
#定义第一个子项1
#定义最后一个子numargc
#定义路径_1“/usr/bin/”
#定义路径2“/bin/”
#定义DUP_READ()\
if(dup2(fdes[READ],fileno(stdin))=-1)\
{ \
perror(“dup错误”)\
出口(4)\
}
#定义DUP_WRITE()\
if(dup2(fdes[WRITE],fileno(stdout))=-1)\
{ \
perror(“dup错误”)\
出口(4)\
}
#定义CLOSE_FDES_READ()\
关闭(fdes[读取]);
#定义CLOSE_FDES_WRITE()\
关闭(fdes[写入]);
#定义EXEC(x,y)\
if(execl(arraycmds[x],argv[y],(char*)NULL)=-1)\
{ \
perror(“执行错误”)\
出口(5)\
}
#定义打印\
printf(“FD-IN:%d\n”,文件号(stdin))\
printf(“FD输出:%d\n”,文件号(stdout));
枚举
{
读取,/*0*/
写
马克斯
};
int cmdfinder(char*cmd,char*path);/*1->已找到,0->未找到*/
int main(int argc,char*argv[])
{
int numargc=argc-1;
char arraycmds[numargc][150];
inti=1,m=0,睡眠时间=5,numfork;
int rc=未找到;
pid_t pid;
int-fdes[2];
如果(管道(fdes)=-1)
{
perror(“管道错误”);
出口(4);
}
虽然(我你所有的宏都让它比你直接写的更难读。特别是当它们涉及局部变量时。要想了解EXEC
的情况,我的眼睛必须从它的使用位置跳到它的定义位置,找出它使用的局部数组,然后再跳回去看看它在fl中是如何使用的这是一个由宏组成的迷宫
哇,cmdfinder
?您自己的$PATH
查找,只是它是硬编码的/usr/bin:/bin
?和双重哇,readdir
,只是为了找出是否存在一个文件,其名称已经确定?只需统计它!或者不做任何事情,只需执行它并通过尝试下一个文件来处理enoint
。或者使用execlp
这就是它的用途
说到要点……您没有足够的管道,并且没有关闭所有未使用的描述符
last | sort | more
是由2个管道连接的3个命令组成的管道。不能使用一个管道。第一个命令应写入第一个管道,中间的命令应读取第一个管道并写入第二个管道,最后一个命令应读取第二个管道
您可以先创建两个管道,然后执行所有分叉,这使操作变得简单,但在每个子进程中都需要大量的close
s,因为它们都将继承所有管道FD。或者您可以使用更复杂的循环,在分叉将使用它的第一个进程之前创建每个管道,并关闭每个描述符或者在相关的子进程创建后立即在父进程中。我不想看到您将使用多少宏
每次成功的dup之后都应该关闭复制的描述符。dup
是“复制”而不是“移动”的缩写。完成后,您将剩下一个额外的描述符,因此不要只关闭dup2(fdes[1],fileno(stdout)
-也要关闭close(fdes[1])
。(为了非常健壮,您应该检查fdes[1]==fileno(stdout)
是否已经存在,在这种情况下,请跳过dup2
和close
)
后续问题
您不能将一个管道用于3个进程,因为无法区分哪些数据应发送到哪个目标。当第一个进程写入管道时,而其他两个进程都试图从中读取数据,其中一个进程将获取数据,但您无法预测是哪一个。您需要中间进程读取数据第一个进程写入,最后一个进程读取中间进程写入的内容
在fork之后共享文件描述符是正确的一半。实际的管道对象是共享的。这就是整个系统工作的原因。但是文件描述符-由小整数指定的端点,如1表示标准输出,0表示标准输入,等等-没有按照您建议的方式耦合。同一管道对象可能是不正确的在两个进程中与相同的文件描述符编号关联,关联是独立的。在一个进程中关闭fd 1不会导致fd 1在任何其他进程中关闭,即使它们是相关的
共享fd表是“pthre”的一部分,以使一项任务中的结束对另一项任务产生影响