Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C程序中的高级I/O重定向。(简单Shell)_C_String_Shell_Unix_Redirect - Fatal编程技术网

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

C程序中的高级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

我正在设计一个简单的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);
           }        
}
我称之为子进程

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*
    函数族:“好的,现在可以停止复制了。”
让我们再跳过确定的错误3,讨论潜在的错误4:这里不清楚是否有
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 >