我有一个解析给定命令的程序,并将所有参数/程序分配给结构。在我执行命令的主程序中,我试图将管道命令的输出重定向到文件,如果是“>”给出。例如,我的程序将成功执行命令
cat filea | grep pattern
但我也希望能够执行命令
cat filea | grep pattern > outfile
作为旁注,理解cmdscan.c的确切机制并不是很重要,因为它是作为辅助程序提供的,它有助于解析命令字符串并填充结构值,这样可以更容易地检查主程序hsh.c中的案例。此外,argv1和argv2是管道的左侧和右侧,因此argv2仅在有管道时才会填满。如果有任何排序的重定向,那么文件的名称将存储在infile / outfile中,具体取决于重定向
这是执行命令的主程序hsh.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <string.h>
#define BUFSIZE 500
struct cmd
{
int redirect_in; /* Any stdin redirection? */
int redirect_out; /* Any stdout redirection? */
int redirect_append; /* Append stdout redirection? */
int background; /* Put process in background? */
int piping; /* Pipe prog1 into prog2? */
char *infile; /* Name of stdin redirect file */
char *outfile; /* Name of stdout redirect file */
char *argv1[10]; /* First program to execute */
char *argv2[10]; /* Second program in pipe */
};
int cmdscan(char *cmdbuf, struct cmd *com);
int main() {
char buf[BUFSIZE];
struct cmd command;
pid_t pid;
int status;
int fd[2];
pipe(fd);
int fdout;
while((fgets(buf,BUFSIZE,stdin) != NULL)) {
if(cmdscan(buf,&command)==-1) {
printf("illegal format\n");
continue;
}
if((pid=fork()) <0)
perror("fork error\n");
if(strcmp(command.argv1[0],"exit") == 0) {
return 0;
}
else if (pid == 0) {
//if the command has piping
if(command.piping){
if((pid = fork()) <0)
perror("fork error");
//fork again so we can do more commands after this one
else if(pid == 0) {
if((pid = fork()) < 0)
perror("fork error");
else if (pid == 0){
//fdout = open(command.outfile, O_CREAT | O_WRONLY);
//dup2(fdout, STDOUT_FILENO);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
execvp(*command.argv1,command.argv1);
} else {
dup2(fd[0],STDIN_FILENO);
close(fd[0]);
execvp(*command.argv2,command.argv2);
}
}
//execute normal command
}else {
//if normal command has redirection
if(command.redirect_out){
fdout = open(command.outfile, O_CREAT | O_WRONLY);
dup2(fdout,STDOUT_FILENO);
close(fd[0]);
execvp(*command.argv1,command.argv1);
}
else{
execvp(*command.argv1,command.argv1);
}
}
//..
exit(0);
} else {
if(wait(&status)!=pid)
perror("wait error");
}
}
return 0;
}
这是解析命令行cmdscan.c。:
的程序#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
struct cmd
{
int redirect_in; /* Any stdin redirection? */
int redirect_out; /* Any stdout redirection? */
int redirect_append; /* Append stdout redirection? */
int background; /* Put process in background? */
int piping; /* Pipe prog1 into prog2? */
char *infile; /* Name of stdin redirect file */
char *outfile; /* Name of stdout redirect file */
char *argv1[10]; /* First program to execute */
char *argv2[10]; /* Second program in pipe */
};
#define TRUE 1
#define FALSE 0
int
cmdscan(char *cmdbuf, struct cmd *com)
{
char *token;
char *curcmd; /* pointer to current command string */
char swtch[256]; /* buffer to hold copy of switch */
char *separators = " \t\n";
int i;
com->redirect_in = FALSE;
com->redirect_out = FALSE;
com->redirect_append = FALSE;
com->background = FALSE;
com->piping = FALSE;
if ( (com->argv1[0] = strtok(cmdbuf,separators) ) == NULL)
return(-1);
i = 1;
while( (com->argv1[i++] = (token = strtok(NULL,separators))) != NULL && strcmp(token,">") &&
strcmp(token,"<") && strcmp(token,">>") && strcmp(token,"&") && strcmp(token,"|") );
com->argv1[i-1] = NULL;
if ( token != NULL && strcmp(token,"|") == 0 )
{
com->piping = TRUE;
i = 0;
while( (com->argv2[i++] = (token = strtok(NULL,separators))) != NULL && strcmp(token,">") &&
strcmp(token,"<") && strcmp(token,">>") && strcmp(token,"&") && strcmp(token,"|") );
com->argv2[i-1] = NULL;
if ( com->argv2[0] == NULL )
return(-1);
}
while ( token != NULL ){
if ( !strcmp(token,">") || !strcmp(token,">>") )
{
if ( com->redirect_out )
return(-1);
com->redirect_out = TRUE;
if ( !strcmp(token,">>") )
com->redirect_append = TRUE;
if ( (com->outfile = strtok(NULL,separators)) == NULL )
return(-1);
}
else if ( !strcmp(token,"<") )
{
if ( com->redirect_in )
return(-1);
com->redirect_in = TRUE;
if ( (com->infile = strtok(NULL,separators)) == NULL )
return(-1);
}
else if ( !strcmp(token,"|") )
{
if ( com->piping )
return(-1);
}
else if ( !strcmp(token,"&") )
{
if ( com->background )
return(-1);
com->background = TRUE;
if ( (token = strtok(NULL,separators)) != NULL )
return(-1);
break;
}
else
return(-1);
token = strtok(NULL,separators);
}
return(0);
}
我尝试使用与简单命令相同的逻辑进行重定向,但我无法使其工作并对管道感到困惑。
答案 0 :(得分:1)
在我们让输出重定向工作之前,需要修复一个基本错误:在pipe
程序中创建一个main
,此pipe
保持打开状态直到程序结束;从管道读取的每个进程直到EOF都不会在main
程序结束之前终止,因此在运行期间输入的管道命令行越多,等待进程就越多(您可以使用{ {1}})。要更正此问题,请在ps
之前为管道流程创建pipe
;此外,您必须在fork
之后关闭管道的两个端(见下文)。
在此之后,输出重定向很简单,类似于 dup2
中的操作,但是您违反了规则:
int open(const char *pathname, int flags, mode_t mode);mode 指定在新文件出现时使用的权限 创建。 O_CREAT 时必须提供此参数 在标志;
中指定
因此,管道代码的核心变为:
if normal command has redirection