我正在设计一个简单的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 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);
}
}
b是这样变化的:
inpu=strtok(str," ");
while(inpu!=NULL){
argsexec[b]=inpu;
b++;
inpu = strtok(NULL, " ");
}
我称之为儿童过程。
if (pid==0){
ioredirection(b);
我希望它是明白的,我的全部是代码真的很长,我试图削减它这样。任何建议都将不胜感激。
最佳答案
我在格式化程序中运行了您的代码,得到(大大简化了):
void ioredirection(int f) {
for (k over all arguments) {
set m based on argsexec[k]
}
test m against 1, 2, and 3
}
因此,如果有两个(或更多)“重新定向”操作,则循环(
for 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*
就永远不会返回。因此,如果需要重定向两个(或更多)值,则最终的*_FILENO
调用必须推迟,直到所有其他重定向都完成。1其中一个不是适当的功能。好吧,不要在这里跳舞:
exec*
是正确的选择。:-)如果重定向后面没有文件名,则会出现第三个问题(请参见下文)。
这个代码片段的最后两个潜在问题不太明显,需要看整个事情。一个是否是“真正的bug”取决于你的shell有多简单。
execvp
数组最多可以容纳128个指针值。argsexec
中的条目应该是要运行的二进制文件的名称,它毕竟是提供给char *
的,要使用argsexec[0]
,execvp
必须是按顺序排列的多个execvp
中的第一个:argsexec[0]
变为char *
(在您调用的程序中),argsexec[0]
变成argv[0]
(程序的第一个参数),argsexec[1]
变成argv[1]
,等等。。。截止日期:
argsexec[2]
,对于最小的整数argv[2]
,是argsexec[i]
:这告诉i
函数族:“好的,现在可以停止复制了。”让我们再跳过明确的错误3,讨论潜在的错误4:这里不清楚是否有
NULL
设置为execv*
。argsexec[i]
到NULL
的参数是最后一个f
参数,因此iodirection
不能是i
;从这个代码片段中,我们无法判断某些(可能是argsexec[i]
th)NULL
是否是f+1
。要使用argsexec[i]
函数,它需要NULL
。如果有一些I/O重定向,您将把一些
execvp
设置为空这将终止数组并使NULL
调用正常工作。如果不是。。。?这会导致潜在的bug#5:在“真正的”Unix shell中,您可以在命令的“中间”放置I/O重定向:
prog > stdout arg1 2> stderr arg2 < stdin arg3
它使用三个参数(
argsexec[i]
、execvp
和prog
)运行arg1
。实际上,您甚至可以将重定向放在第一位:<stdin >stdout 2>stderr prog arg1 arg2 arg3
在某些shell中,您可以多次“重新定向”(如果不需要,甚至不必运行命令):
$ ls
$ > foo > bar > baz
$ ls
bar baz foo
(但其他炮弹禁止:
$ rm *; exec csh -f
% > foo > bar > baz
Ambiguous output redirect.
并不是说csh可以效仿。:-) )
如果这是一个很大的“If”-您想要允许这个或类似的东西,您将需要“执行并删除”每个I/O重定向,将剩余的参数向下移动,使
arg2
保持“密集填充”状态,其中包含要提供给程序的各种arg3
值。例如,如果argsexec
是数组中有效的非char *
项的长度,因此len
是NULL
,您需要“删除”argsexec[len]
和NULL
(它们分别包含类似“>”的重定向和文件名),则:for (i = j + 2; i <= len; i++) {
argsexec[i - 2] = argsexec[i];
}
就可以了(循环运行到
argsexec[j]
以便它也复制终止的argsexec[j + 1]
)。最后,确定的错误3:如果重定向位于最后一个位置,会发生什么?
i <= len
循环从NULL
运行到argsexec[f - 1]
包含。如果for (k ...)
,k
是重定向,则文件名必须在0
中。但我们刚刚注意到(上面)需要
f - 1
。也就是说,如果有人试图:ls >
那么
k == f - 1
应该包含argsexec[k]
、argsexec[f]
和argsexec[f]
。在这种情况下,“真壳”和“真壳”的作用如下:
$ ls >
Syntax error: newline unexpected
% ls >
Missing name for redirect.
如果重定向后的文件名丢失,则需要类似的方法:拒绝尝试。
关于c - C程序中的高级I/O重定向。(简单Shell),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20457727/