![](/img/trans.png)
[英]How to redirect the output of 'ls' (or any other shell command) to a pipe?
[英]How to redirect output from pipe command to a file
我有一个解析给定命令的程序,并将所有参数/程序分配给一个struct。 在我执行命令的主程序中,如果给出“>”,我试图将管道命令的输出重定向到文件。 例如,我的程序将成功执行命令
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);
}
我尝试使用与简单命令相同的逻辑进行重定向,但我无法使其工作并且对管道感到困惑。
在我们让输出重定向工作之前,需要修复一个基本错误:在main
创建一个pipe
,并且该pipe
保持打开状态直到程序结束; 从管道读取的每个进程直到EOF都不会在main
结束之前终止,因此在运行期间输入的管道命令行越多,等待的进程就越多(你可以用ps
来观察)。 为了解决这个问题,创建pipe
只是之前fork
的管道过程; 此外,您必须在后关闭管道两端 dup2
(见下文)。
在此之后,输出重定向很简单,类似于if normal command has redirection
,但是您违反了规则:
int open(const char * pathname,int flags,mode_t mode);specifies the permissions to use in case a new file is created. 指定在创建新文件时使用的权限。 ; 当在指定O_CREAT时,必须提供此参数;
因此,管道代码的核心变为:
pipe(fd);
if ((pid = fork()) < 0)
perror("fork error");
else if (pid == 0) {
dup2(fd[1], STDOUT_FILENO);
close(fd[0]); // close both fd in child
close(fd[1]);
execvp(*command.argv1, command.argv1);
} else {
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]); // close both fd in parent
if (command.redirect_out)
{
fdout =
open(command.outfile, O_CREAT|O_WRONLY|O_TRUNC, 0666);
dup2(fdout, STDOUT_FILENO);
}
execvp(*command.argv2, command.argv2);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.