C程序中的高级I / O重定向。(简单Shell)

时间:2013-12-08 19:13:38

标签: c string shell unix redirect

我正在设计一个简单的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);

我希望很明白,我的完整代码真的很长,我试图像这样削减它。任何建议将不胜感激。

1 个答案:

答案 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并使用execvpargsexec[0]必须是第一个char *按顺序排列:

  • argsexec[0]变为argv[0](在您调用的程序中),
  • argsexec[1]变成argv[1](程序的第一个参数),
  • argsexec[2]变为argv[2]
  • 依此类推......直到:
  • argsexec[i],对于最小的整数i,为NULL:并告诉execv*系列函数:“好的,您现在可以停止复制。”< / LI>

让我们跳过确定的错误#3一段时间,然后讨论潜在的错误#4:这里不清楚是否有argsexec[i]被设置为NULLfiodirection的参数是 last iargsexec[i]必须 NULL ;我们无法从这段代码片段中判断出一些(可能是f+1argsexec[i]NULL。要使用execvp功能,需要NULL

如果存在一些I / O重定向,则会将一些argsexec[i]设置为NULL。这将终止数组并使execvp调用正常工作。如果不是......?

这导致了潜在的错误#5:在“真正的”Unix shell中,你可以在命令的“中间”放置I / O重定向:

prog > stdout arg1 2> stderr arg2 < stdin arg3

这会运行prog三个参数(arg1arg2arg3)。实际上,您甚至可以将重定向放在第一位:

<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条目的长度,那么NULLargsexec[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。如果0f - 1是重定向,则文件名必须位于k == f - 1

但我们刚才注意到(上文)argsexec[k] 需要argsexec[f]。也就是说,如果有人试图:

argsexec[f]

然后NULL应包含ls > argsexec[]"ls"

以下是“真实炮弹”">"NULL在这种情况下的行为:

sh

如果缺少重定向后的文件名,则需要类似的东西:拒绝尝试的方法。