【发布时间】:2013-12-21 19:14:35
【问题描述】:
我有一个程序可以解析给定的命令,并将所有参数/程序分配给一个结构。在执行命令的主程序中,如果给出“>”,我试图将管道命令的输出重定向到文件。比如我的程序会成功执行命令
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);
}
我尝试应用与简单重定向命令相同的逻辑,但我无法让它工作并且对管道有点困惑。
【问题讨论】:
-
重定向实际上是相当复杂的,你有没有考虑过
cat filea 2>&1 | grep pattern,它将stderr重定向到stdout,然后再通过grep进行管道传输? -
起初我尝试将 stdout 更改为 fdout,类似于 else 语句中的一般命令,但这是不行的。然后我在讲义中读到应该在程序 2 中处理管道情况下的输出重定向,所以我也在那里尝试过,但很困惑,因为程序 2 从管道的读取端处理 STDIN。我尝试了很多不同的组合,但它不起作用。我对那个命令有点困惑。我知道
cat filea | grep pattern会起作用。 -
我在运行该命令时得到
cat: 2>&: No such file or directory。
标签: c linux shell redirect pipe