C程序中的高级I/O重定向。(简单Shell)
我正在设计一个简单的shell,但是高级重定向有问题 我可以这样做:ls-al>a.txt 但是我不能这样做:wcC程序中的高级I/O重定向。(简单Shell),c,string,shell,unix,redirect,C,String,Shell,Unix,Redirect,我正在设计一个简单的shell,但是高级重定向有问题 我可以这样做:ls-al>a.txt 但是我不能这样做:wcb.txt 我该怎么做 以下是我执行i/o重定向的位置: char *inpu=NULL; //Inpu is a global variable. #define CREATE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC) #define CREATE_FLAGS1 (O_WRONLY | O_CREAT | O_APPEND) #define CREA
char *inpu=NULL; //Inpu is a global variable.
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC)
#define CREATE_FLAGS1 (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_FLAGS2 (O_RDONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define MAXCHARNUM 128
#define MAXARGNUM 32
char *argsexec[MAXARGNUM]; /*This stores my executable arguments like cd ls.*/
void ioredirection(int f){
int k,i,m;
int input=-1;
int output=-1;
int append=-1;
int fdin,fdout;
for(k=0; k<f; k++){
if(strcmp(argsexec[k],"<")==0){
input=k; // argument place of "<"
m=1;
argsexec[k]=NULL;
}
else if(strcmp(argsexec[k],">")==0){
output=k; // argument place of ">"
m=2;
argsexec[k]=NULL;
}
else if(strcmp(argsexec[k],">>")==0){
append=k; // argument place of ">>"
m=3;
argsexec[k]=NULL;
}
}
if(m==1){
int inp1;
fdin=open(argsexec[input+1],O_RDONLY,CREATE_MODE);
dup2(fdin,STDIN_FILENO);
close(fdin);
inp1=execlp(argsexec[0],argsexec[0],NULL);
}
if(m==2){
fdout = open(argsexec[output+1], CREATE_FLAGS, CREATE_MODE);
dup2 (fdout, STDOUT_FILENO);
close(fdout);
execvp(argsexec[0],argsexec);
}
if(m==3){
fdout = open(argsexec[append+1], CREATE_FLAGS1, CREATE_MODE) ;
dup2 (fdout, STDOUT_FILENO);
close(fdout);
execvp(argsexec[0],argsexec);
}
}
我称之为子进程
if (pid==0){
ioredirection(b);
我希望这是清楚地理解,我的完整代码真的很长,我试图削减它这样。如果您有任何建议,我们将不胜感激。我通过格式化程序运行了您的代码,得到了(大大简化): 因此,如果有两个(或多个)“重新定向”操作,循环(
用于k
)将设置m
两次(或更多)。然后,循环终止,您(最终)针对三个可能的值中的每一个测试m
第一个问题现在应该很清楚了(但由于这是一个学校项目,我不打算为您解决它:-))
第二个问题只有在查看在m
上执行的三个测试时才清楚。在这里只看一个就足够了:
if (m == 1) {
int inp1;
fdin = open(argsexec[input + 1], O_RDONLY, CREATE_MODE);
dup2(fdin, STDIN_FILENO);
close(fdin);
inp1 = execlp(argsexec[0], argsexec[0], NULL);
}
(另外两个使用execvp
而不是execlp
.1)如果exec*
系列函数调用成功,将立即替换当前进程,从而exec*
永远不会返回。因此,如果需要重定向两个(或更多)的*\u FILENO
值,则最终的exec*
调用必须推迟到所有其他重定向完成之后
1其中一项不是适当的功能。好的,不要在这里跳舞:
execvp
是正确的选择。:-)
如果重定向后面没有文件名,则会出现第三个问题(请参见下文) 这个代码片段的最后两个潜在问题就不那么明显了,需要仔细研究一下。一个是否是“真正的bug”取决于shell的简单程度
argsexec
数组最多可容纳128个char*
指针值。argsexec[0]
中的条目应该是二进制文件的名称,以运行它提供给execvp
,并且要使用execvp
,argsexec[0]
必须是顺序中的第一个char*
s:
变为argsexec[0]
(在您调用的程序中)argv[0]
变为argsexec[1]
(程序的第一个参数)argv[1]
变为argsexec[2]
argv[2]
- 等等。。。直至:
,对于最小的整数argsexec[i]
,它是i
:这告诉NULL
函数族:“好的,现在可以停止复制了。”execv*
argsexec[i]
被设置为NULL
。f
到i方向
的参数是最后一个i
,其argsexec[i]
不得为NULL
;从这个代码片段中,我们无法判断一些(可能是f+1
th)argsexec[i]
是否为NULL
。要使用execvp
函数,它必须为NULL
如果存在一些I/O重定向,您将把一些argsexec[I]
设置为NULL。这将终止数组并使execvp
调用正常工作。如果不是
这导致了潜在的bug#5:在“真正的”Unix shell中,您可以在命令的“中间”放置I/O重定向:
prog > stdout arg1 2> stderr arg2 < stdin arg3
在某些shell中,您可以多次“重定向”(如果不需要命令,甚至不用运行命令):
(但其他炮弹禁止:
$rm*;exec csh-f
%>foo>bar>baz
输出重定向不明确。
并不是说csh是可以模仿的。:-)
如果这是一个很大的“如果”-您希望允许此操作或类似操作,则需要“执行并删除”每个I/O重定向,并向下移动剩余参数,以便argsexec
仍然“密集填充”将提供给程序的各种char*
值。例如,如果len
是数组中有效的非NULL
项的长度,因此argsexec[len]
是NULL
,您需要“删除”argsexec[j]
和argsexec[j+1]
(分别包含类似“>”的重定向和文件名),那么:
然后,argsexec[]
应该包含“ls”
,“>”
,和NULL
下面是在这种情况下“真正的shell”sh
和csh
所做的:
$ls>
语法错误:换行符意外
%ls>
缺少重定向的名称。
您将需要类似的东西:如果重定向后的文件名丢失,则需要一种拒绝尝试的方法。我通过格式化程序运行了您的代码,得到(大大简化了): 因此,如果有两个(或多个)“重新定向”操作,循环(
用于k
)将设置m
两次(或更多)。然后,循环终止,您(最终)针对三个可能的值中的每一个测试m
第一个问题现在应该很清楚了(但由于这是一个学校项目,我不打算为您解决它:-))
第二个问题只有在查看在m
上执行的三个测试时才清楚。在这里只看一个就足够了:
if (m == 1) {
int inp1;
fdin = open(argsexec[input + 1], O_RDONLY, CREATE_MODE);
dup2(fdin, STDIN_FILENO);
close(fdin);
inp1 = execlp(argsexec[0], argsexec[0], NULL);
}
(另外两个使用execvp
而不是execlp
.1)如果exec*
系列函数调用成功,将立即替换当前进程,从而exec*
永远不会返回。因此,如果需要重定向两个(或更多)的*\u FILENO
值,则最终的exec*
调用必须推迟到所有其他重定向完成之后
1其中一个不是
prog > stdout arg1 2> stderr arg2 < stdin arg3
$ ls
$ > foo > bar > baz
$ ls
bar baz foo
for (i = j + 2; i <= len; i++) {
argsexec[i - 2] = argsexec[i];
}
ls >