我正在设计一个简单的shell,但我遇到了高级重定向问题。
我能够做到这一点:ls -al> a.txt
但我不能这样做:wc< a.txt> b.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);
我希望很明白,我的完整代码真的很长,我试图像这样削减它。任何建议将不胜感激。
答案 0 :(得分:3)
我通过格式化程序运行代码并得到(大大简化):
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
值,则必须推迟最终exec*
调用,直到所有其他重定向也完成后。
1 其中一个不是合适的功能。好的,不要在这里跳舞:execvp
是正确的选择。 : - )
如果重定向后面没有文件名,则会出现第三个问题(见下文)。
此代码段的最后两个潜在问题不太明显,需要查看整个问题。一个人是否是“真正的错误”取决于你的shell的简单程度。
argsexec
数组最多可包含128个char *
指针值。 argsexec[0]
中的条目应该是要运行的二进制文件的名称 - 它毕竟提供给execvp
并使用execvp
,argsexec[0]
必须是第一个char *
按顺序排列:
argsexec[0]
变为argv[0]
(在您调用的程序中),argsexec[1]
变成argv[1]
(程序的第一个参数),argsexec[2]
变为argv[2]
,argsexec[i]
,对于最小的整数i
,为NULL
:并告诉execv*
系列函数:“好的,您现在可以停止复制。”< / LI>
让我们跳过确定的错误#3一段时间,然后讨论潜在的错误#4:这里不清楚是否有argsexec[i]
被设置为NULL
。 f
到iodirection
的参数是 last i
,argsexec[i]
必须不 NULL
;我们无法从这段代码片段中判断出一些(可能是f+1
)argsexec[i]
是NULL
。要使用execvp
功能,需要NULL
。
如果存在一些I / O重定向,则会将一些argsexec[i]
设置为NULL。这将终止数组并使execvp
调用正常工作。如果不是......?
这导致了潜在的错误#5:在“真正的”Unix shell中,你可以在命令的“中间”放置I / O重定向:
prog > stdout arg1 2> stderr arg2 < stdin arg3
这会运行prog
三个参数(arg1
,arg2
和arg3
)。实际上,您甚至可以将重定向放在第一位:
<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重定向,将剩余的参数移动到{{1使用要提供给程序的各种argsexec
值保持“密集填充”。例如,如果char *
是数组中有效的非len
条目的长度,那么NULL
为argsexec[len]
,并且您需要“删除”{ {1}}和NULL
(分别包含“&gt;”重定向和文件名),然后:
argsexec[j]
可以解决问题(循环运行到argsexec[j + 1]
,以便它也复制终止for (i = j + 2; i <= len; i++) {
argsexec[i - 2] = argsexec[i];
}
。
所以,最后,明确的错误#3:如果重定向位于最后一个位置i <= len
会发生什么? NULL
循环从argsexec[f - 1]
到for (k ...)
运行k
。如果0
,f - 1
是重定向,则文件名必须位于k == f - 1
。
但我们刚才注意到(上文)argsexec[k]
需要为argsexec[f]
。也就是说,如果有人试图:
argsexec[f]
然后NULL
应包含ls >
,argsexec[]
和"ls"
。
以下是“真实炮弹”">"
和NULL
在这种情况下的行为:
sh
如果缺少重定向后的文件名,则需要类似的东西:拒绝尝试的方法。