![](/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.