综合实例:⽤C语⾔实现⼀个⾃定义的shell程序
⼀个shell需要实现若⼲功能,⽐如解释执⾏命令,⽀持输⼊输出重定向,⽀持管道,后台运⾏程序等。⾸先对要实现的功能做⼀个简要介绍:
(1)输出重定向:就是把执⾏某命令后的结果输出到某个⽂件。例如:
ls -al >
(2)输⼊重定向:这⾥的<;不是类似于输出重定向中的操作符>,⽽是从⽂件中取出数据到指定的⽂件中。例如:
cat > newfile < test3
上述命令将test3中的数据取出,然后输⼊到newfile这个⽂件中。
(3)管道:就是先后执⾏2个命令,把前⼀个命令的结果当成后⼀个命令的输⼊。例如:
ls -a | grep mysql
上例就是先显⽰所有⽂件,然后在ls命令的显⽰结果⾥⽤grep命令查包含mysql的⽂件。
(4)命令后台运⾏:可以在命令结尾加⼀个&让此程序在后台运⾏,即使shell关闭也不影响程序的继续执⾏。
关键函数的功能及说明
(1)void print_prompt()
本函数只打印myshell的提⽰符,即“myshell$$”。
(2)void get_input(char *buf)
获得⼀条⽤户输⼊的待执⾏的命令,参数buf⽤于存放输⼊的命令。如果输⼊的命令过长(⼤于256个字符),则终⽌程序。命令以换⾏
符“\n”作为结束标志。
(3)void explain_input(char *buf, int *argcount, char arglist[100][256])
解析buf中存放的命令,把每个选项存放在arglist中。如输⼊的命令“ls -l /tmp”,则arglist[0]、arglist[1]、arglist[2]指向的字符串分别为“ls”、“-l”、“/tmp”。
执⾏arglist中存放的命令,argcount为待执⾏命令的参数个数。
(5)int find_command(char *command)
功能是分别在当前⽬录下、/bin、/usr/bin⽬录下查命令的可执⾏程序。myshell.c程序源代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#define normal 0 /* ⼀般的命令 */
#define out_redirect 1 /* 输出重定向 */
#define in_redirect 2 /* 输⼊重定向 */
#define have_pipe 3 /* 命令中有管道 */
void print_prompt(); /* 打印提⽰符 */
void get_input(char *); /* 得到输⼊的命令 */
//⼆维数组作为形参,必须指明列的数字
void explain_input(char *, int *, char a[ ][256]); /* 对输⼊命令进⾏解析 */
void do_cmd(int, char a[ ][256]); /* 执⾏命令 */
int find_command(char *); /* 查命令中的可执⾏程序 */
int main(int argc, char **argv)一个完整的c语言程序
{
int i;
int argcount = 0;
char arglist[100][256];
char **arg = NULL;
char *buf = NULL;
buf = (char *)malloc(256);
if( buf == NULL ) {
perror("malloc failed");
exit(-1);
}
while(1) {
/* 将buf所指向的空间清零 */
memset(buf, 0, 256);
print_prompt();
get_input(buf);
/* 若输⼊的命令为exit或logout则退出本程序 */
if( strcmp(buf,"exit\n") == 0 || strcmp(buf,"logout\n") == 0 )
break;
for (i=0; i < 100; i++)
{
arglist[i][0]='\0';
}
argcount = 0;
explain_input(buf, &argcount, arglist);
do_cmd(argcount, arglist);
}
if(buf != NULL) {
free(buf);
buf = NULL;
}
exit(0);
}
void print_prompt()
{
printf("myshell$$ ");
}
/*获取⽤户输⼊*/
void get_input(char *buf)
{
int len = 0;
int ch;
ch = getchar();
while (len < 256 && ch != '\n') {
buf[len++] = ch;
ch = getchar();
}
if(len == 256) {
printf("command is too long \n");
exit(-1); /* 输⼊的命令过长则退出程序 */
}
buf[len] = '\n';
len++;
buf[len] = '\0';
}
/* 解析buf中的命令,将结果存⼊arglist中,命令以回车符号\n结束 */
/* 例如输⼊命令为"ls -l /tmp",则arglist[0]、arglist[1]、arglsit[2]分别为ls、-l和/tmp */ void explain_input(char *buf, int *argcount, char arglist[100][256])
{
char *p = buf;
char *q = buf;
int number = 0;
while (1) {
if ( p[0] == '\n' )
break;
if ( p[0] == ' ' )
p++;
else {
q = p;
number = 0;
while( (q[0]!=' ') && (q[0]!='\n') ) {
number++;
q++;
}
strncpy(arglist[*argcount], p, number+1);
arglist[*argcount][number] = '\0';
*argcount = *argcount + 1;
p = q;
}
}
}
void do_cmd(int argcount, char arglist[100][256])
{
int how = 0; /* ⽤于指⽰命令中是否含有>、<、| */
int background = 0; /* 标识命令中是否有后台运⾏标识符& */
int status;
int i;
int fd;
char* arg[argcount+1];
char* argnext[argcount+1];
char* file;
pid_t pid;
/*将命令取出*/
for (i=0; i < argcount; i++) {
arg[i] = (char *) arglist[i];
}
arg[argcount] = NULL;
/*查看命令⾏是否有后台运⾏符*/
for (i=0; i < argcount; i++) {
if (strncmp(arg[i], "&",1) == 0) {
if (i == argcount-1) {
background = 1;
arg[argcount-1] = NULL;
break;
}
else {
printf("wrong command\n");
return ;
}
}
}
for (i=0; arg[i]!=NULL; i++) {
if (strcmp(arg[i], ">") == 0 ) {
flag++;
how = out_redirect;
if (arg[i+1] == NULL)
flag++;
}
if ( strcmp(arg[i],"<") == 0 ) {
flag++;
how = in_redirect;
if(i == 0)
flag++;
}
if ( strcmp(arg[i],"|")==0 ) {
flag++;
how = have_pipe;
if(arg[i+1] == NULL)
flag++;
if(i == 0 )
flag++;
}
}
/* flag⼤于1,说明命令中含有多个> ,<,|符号,本程序是不⽀持这样的命令的或者命令格式不对,如"ls -l /tmp >" */
if (flag > 1) {
printf("wrong command\n");
return;
}
if (how == out_redirect) { /*命令只含有⼀个输出重定向符号> */
for (i=0; arg[i] != NULL; i++) {
if (strcmp(arg[i],">")==0) {
file = arg[i+1];
}
}
}
if (how == in_redirect) { /*命令只含有⼀个输⼊重定向符号< */
for (i=0; arg[i] != NULL; i++) {
if (strcmp (arg[i],"<") == 0) {
file = arg[i+1];
arg[i] = NULL;
}
}
}
if (how == have_pipe) { /* 命令只含有⼀个管道符号| */
/* 把管道符号后门的部分存⼊argnext中,管道后⾯的部分是⼀个可执⾏的shell命令 */ for (i=0; arg[i] != NULL; i++) {
if (strcmp(arg[i],"|")==0) {
arg[i] = NULL;
int j;
for (j=i+1; arg[j] != NULL; j++) {
argnext[j-i-1] = arg[j];
}
argnext[j-i-1] = arg[j];
break;
}
}
}
if ( (pid = fork()) < 0 ) {
printf("fork error\n");
return;
}
switch(how) {
case 0:
/* pid为0说明是⼦进程,在⼦进程中执⾏输⼊的命令 */
/
* 输⼊的命令中不含>、<;和| */
if (pid == 0) {
if ( !(find_command(arg[0])) ) {
printf("%s : command not found\n", arg[0]);
exit (0);
}
execvp(arg[0], arg);
exit(0);
}
break;
case 1:
/
* 输⼊的命令中含有输出重定向符> */
if (pid == 0) {
if ( !(find_command(arg[0])) ) {
printf("%s : command not found\n",arg[0]);
exit(0);
}
fd = open(file,O_RDWR|O_CREAT|O_TRUNC,0644);
dup2(fd,1);
execvp(arg[0],arg);
exit(0);
}
break;
case 2:
/* 输⼊的命令中含有输⼊重定向符< */
if (pid == 0) {
if ( !(find_command (arg[0])) ) {
printf("%s : command not found\n",arg[0]);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论