当前位置:   article > 正文

Linux内核编程实验二_将进程标准输入和fds管道读端相关联

将进程标准输入和fds管道读端相关联

1、实验名称:shell命令解释系统设计实验
2、实验要求:
问题 A:
实现一个能处理前后台运行命令的 shell。
问题 B:
实现一个带有管道功能的 shell。
问题 C:
实现一个能处理 I/O 重定向的 shell。
问题 D:
实现一个能在一行上处理多条命令的 shell。
将问题 A-D 集中到一个 shell 解析程序中。

3、解决思路
第一步解决问题D。一行上多条命令使用 ; 分开,;两边可以有空格,也可以没有,或者都考虑(健壮性),本方案采用没空格。根据 ; 将其拆分成多条命令,逐条执行即可。

第二步解决问题A。让进程在后台运行,意味着父进程不需要等待子进程运行完毕。否则使用waitpid()函数让父进程等待一下即可。

第三步解决输出重定向,即问题C。根据定向符 > 获得后面的文件名。使用open()打开,使用dup2()函数将标准输出重定向到该文件。那么该进程的输出都将添加到文件中,而不是终端。通常在子进程内进行相应操作。

第四步解决输出重定向,问题C。根据输入定向符 < 获得后面文件名。使用open打开。使用dup2将标准输入重定向到该文件,那么该进程将使用该文件作为输入,而不是终端。

第五步解决管道问题。此处使用匿名管道。匿名管道使用pipe(fds)创建。fds为int类型长度为2的数组。fds[0]为读取数据端。fds[1]为写入数据端。创建两个进程一个管道。进程1关闭读端,将标准输出重定向到管道写端,将数据暂时保存在管道内。进程2关闭写端,将标准输入重定向到管道读端,将管道内数据读出,完成进程通信。

不足之处,仅供参考:

缺点一是支持格式有限。比如
普通命令:ls -a /bin //加粗部分必须为全路径
输出重定向:ls /bin > /home/me/shiyan/test.c //>两侧必须空格
输入重定向:cat < /home/me/shiyan/test.c
管道:cat /home/me/shiyan/test.c | sort //管道两端命令不支持出现重定向
//管道符号两侧必须有空格
后台运行:ls /bin > /home/me/shiyan/test.c& //&符号必须紧跟着
多条命令:ls /home;ls /bin //多条命令分号两边无空格
所有测试命令必须严格遵循上面的格式,否则将可能导致错误的运行结果。

另外一个缺点是,没有完整测试所有linux命令,只测试了部分简单常用命令,因此可能部分命令不支持。


4、实现代码

#include <stdio.h>
#include <string.h> //strlen()
#include <unistd.h> //fork()
#include <sys/types.h> //pid_t
#include <sys/wait.h> //waitpid()
#include <stdlib.h> //exit()
#include <fcntl.h> //open()

#define MAXLEN 80
#define MAXPARA 8

int checkpipe(char *command,int comlen)//判断是否包含|
{
    int i;
    for(i=0; i<comlen; i++)
    {
        if(command[i] == '|')
            return i;
    }
    return -1;
}

int checkout(char *command,int comlen)//判断是否包含>
{
    int i;
    for(i=0; i<comlen; i++)
    {
        if(command[i] == '>')
            return 1;
    }
    return 0;
}

int checkin(char *command,int comlen) //判断是否包含<
{
    int i;
    for(i=0; i<comlen; i++)
    {
        if(command[i] == '<')
            return 1;
    }
    return 0;
}

void runcommand(char *command)
{
    int comlen = strlen(command);
    int backrun = 0;
    char *argv1[MAXPARA],*argv2[MAXPARA];
    int index1,index2;
    int i,fd,pipei,fds[2];
    char *filename;
    pid_t p1,p2;

    if(command[comlen-1] == '&')//是否后台运行
    {
        backrun = 1;
        command[comlen-1] = 0;
        comlen--;
    }
    pipei = checkpipe(command,comlen); 
    if(pipei > -1)//有管道
    {
        command[pipei-1] = 0;
        command[pipei] = 0;
        command[pipei+1] = 0;

        index1 = 0;
        argv1[index1++] = command;
        for(i=0; i<pipei-1; i++)
        {
            if(command[i] == ' ')
            {
                command[i] = 0;
                argv1[index1++] = &command[i+1];
            }
        }
        argv1[index1] = NULL;

        i = pipei + 2;
        index2 = 0;
        argv2[index2++] = &command[i];
        for(; i<comlen; i++)
        {
            if(command[i] == ' ')
            {
                command[i] = 0;
                argv2[index2++] = &command[i+1];
            }
        }
        argv2[index2] = NULL;
        //命令处理完毕,建立管道,进程
        pipe(fds);
        p1 = fork();
        if(p1 == 0)
        {
            close(fds[0]);//关闭读端
            close(STDOUT_FILENO);
            dup2(fds[1],STDOUT_FILENO);//重定向
            close(fds[1]);
            execvp(argv1[0],argv1);//该函数执行后进程结束
        }
        else
        {
            if(backrun == 0)
                waitpid(p1,NULL,0);
            p2 = fork();
            if(p2 == 0)
            {
                close(fds[1]);
                close(STDIN_FILENO);
                dup2(fds[0],STDIN_FILENO);
                close(fds[0]);
                execvp(argv2[0],argv2);
            }
            else
            {
                //父进程关闭管道,让两个子进程进行通信
                close(fds[0]);
                close(fds[1]);
                waitpid(p2,NULL,0);
            }
        }
    }
    else
    {
        if(checkout(command,comlen) == 1)//输出重定向
        {
            index1 = 0;
            argv1[index1++] = command;
            for(i=0; i<comlen; i++)
            {
                if(command[i] == ' ')
                {
                    command[i] = 0;
                    if(command[i+1] == '>')
                        break;
                    argv1[index1++] = &command[i+1];
                }
            }
            argv1[index1] = NULL;
            i = i + 3;
            filename = &command[i];

            p1 = fork();
            if(p1 == 0)
            {
                fd = open(filename,O_WRONLY);
                close(STDOUT_FILENO);
                dup2(fd,STDOUT_FILENO);
                close(fd);
                execvp(argv1[0],argv1);
            }
            else
            {
                if(backrun == 0)
                {
                    waitpid(p1,NULL,0);
                }
            }
        }
        else if(checkin(command,comlen) == 1)//输入重定向
        {
            index1 = 0;
            argv1[index1++] = command;
            for(i=0; i<comlen; i++)
            {
                if(command[i] == ' ')
                {
                    command[i] = 0;
                    if(command[i+1] == '<')
                        break;
                    argv1[index1++] = &command[i+1];
                }
            }
            argv1[index1] = NULL;
            i = i + 3;
            filename = &command[i];

            p1 = fork();
            if(p1 == 0)
            {
                fd = open(filename,O_RDONLY);
                close(STDIN_FILENO);
                dup2(fd,STDIN_FILENO);
                close(fd);
                execvp(argv1[0],argv1);
            }
            else
            {
                if(backrun == 0)
                {
                    waitpid(p1,NULL,0);
                }
            }
        }
        else//普通命令
        {
            index1 = 0;
            argv1[index1++] = command;
            for(i=0; i<comlen; i++) 
            {
                if(command[i] == ' ')
                {
                    command[i] = 0;
                    argv1[index1++] = &command[i+1];
                }
            }
            argv1[index1] = NULL;

            p1 = fork();
            if(p1 == 0)
            {
                execvp(argv1[0],argv1);
            }
            else
            {
                if(backrun == 0)
                {
                    waitpid(p1,NULL,0);
                }
            }
        }
    }
}

int main()
{
    char linebuf[MAXLEN], *command;
    int buflen,i;

    while(1)
    {
        write(STDOUT_FILENO,"$",1);
        fgets(linebuf,MAXLEN,stdin);
        buflen = strlen(linebuf);
        if(linebuf[buflen-1] == '\n')
        {
            linebuf[buflen-1] = 0;
            buflen--;
        }

        if(strcmp(linebuf,"exit") == 0)
            exit(0);
        else
        {
            command = linebuf;
            for(i=0; i<buflen; i++)
            {
                if(linebuf[i] == ';')
                {
                    linebuf[i] = 0;
                    runcommand(command); //循环执行多条命令
                    command = &linebuf[i+1];
                }
            }
            runcommand(command); //多条命令最后一条
        }
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261

5、程序的健壮性优化请参阅:
http://www.powerxing.com/unix-simple-shell-with-argv/

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/675110
推荐阅读
相关标签
  

闽ICP备14008679号