This project consists of designing a C program to serve as a shell interface
that accepts user commands and then executes each command in a separate
process. This project can be completed on any Linux, UNIX, or Mac OS X system.
A shell interface gives the user a prompt, after which the next command
is entered. The example below illustrates the prompt osh> and the user’s
next command: cat prog.c. (This command displays the file prog.c on the
terminal using the UNIX cat command.)
osh> cat prog.c
One technique for implementing a shell interface is to have the parent process
first read what the user enters on the command line (in this case, cat
prog.c), and then create a separate child process that performs the command.
Unless otherwise specified, the parent process waits for the child to exit
before continuing. This is similar in functionality to the new process creation
illustrated in Figure 3.10. However, UNIX shells typically also allow the child
process to run in the background, or concurrently. To accomplish this, we add
an ampersand (&) at the end of the command. Thus, if we rewrite the above
command as
osh> cat prog.c &
the parent and child processes will run concurrently.
The separate child process is created using the fork() system call, and the
user’s command is executed using one of the system calls in the exec() family
(as described in Section 3.3.1).
A C program that provides the general operations of a command-line shell
is supplied in Figure 3.36. The main() function presents the prompt osh->
and outlines the steps to be taken after input from the user has been read. The
main() function continually loops as long as should run equals 1; when the
user enters exit at the prompt, your program will set should run to 0 and
terminate.
This project is organized into two parts: (1) creating the child process and
executing the command in the child, and (2) modifying the shell to allow a
history feature.
相关原理与知识(完成实验所用到的相关原理与知识)
Linux 进程相关基础知识。
Linux下C语言编程。
如何使用终端颜色控制字符调整终端输出字符的颜色。
命令行解析。
实验过程(清晰展示实际操作过程,相关截图及解释)
模型归纳
一个典型的shell可以简化为以下形式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
while(1){init();read_command();intpid=fork();if(pid<0){puts("Unable to fork the child, inner error.");}elseif(pid==0)// the child thread
{execve(command);//execve the command
}else// the parent thread
{wait(NULL);//waiting for the child to exit
}}
if(strcmp(args[0],"cd")==0){if(chdir(args[1])==-1){PrintRed("z-shell: error!\n");fflush(stdout);continue;}else{PrintBlue("z-shell: you are now in ");printf("%s\n",args[1]);fflush(stdout);}continue;}if(strcmp(args[0],"exit")==0){printf("Bye bye! Thanks to use z-shell!\n");fflush(stdout);break;}
chdir函数能够实现切换工作目录的功能,若出现错误,则返回-1。exit较简单,不再赘述。
实现命令执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(strcmp(args[args_count-1],"&")==0){flag=FLAG_EXECVE_NOTWAIT;}pid_tpid=fork();if(pid==-1){PrintRed("z-shell: an error occurred while forking\n");fflush(stdout);}elseif(pid==0){intfl=execvp(args[0],args);if(fl==-1){PrintRed("z-shell: unable to execute the programme ");printf("%s.\n",args[0]);fflush(stdout);}exit(0);}elseif(flag==FLAG_EXECVE_WAIT)wait(NULL);
typedefstructhistory{char*buf[MAX_HISTORY];inthis_count;}history;if(strcmp(args[0],"!!")==0){if(his.his_count==0){PrintRed("z-shell: no commands in history!\n");continue;}strcpy(buffer,his.buf[his.his_count]);gotoPARSER;}if(strcmp(args[0],"!")==0){if(args_count==1){PrintRed("z-shell: please input number!\n");continue;}intnum=atoi(args[1]);if(num==-1){PrintRed("z-shell: number illegal!\n");continue;}intcur=his.his_count-num+1;if(cur<=0){PrintRed("z-shell: no commands in history!\n");continue;}strcpy(buffer,his.buf[cur]);gotoPARSER;}