shell是一个用C编写的应用程序,用户可通过其提供的界面访问os的内核服务。
Linux命令有内部命令(内建命令)和外部命令之分,内部命令和外部命令功能基本相同,但也有些细微差别。
- 内部命令:
实际上是shell程序的一部分,其中包含的是一些比较简单的linux系统命令,这些命令由shell程序识别并在shell程序内部完成运行,通常在linux系统加载运行时shell就被加载并驻留在系统内存中。内部命令是写在bashy源码里面的,其执行速度比外部命令快,因为解析内部命令shell不需要创建子进程。比如:exit,history,cd,echo等。
- 外部命令:
linux系统中的实用程序部分,因为实用程序的功能通常都比较强大,所以其包含的程序量也会很大,在系统加载时并不随系统一起被加载到内存中,而是在需要时才将其调用内存。通常外部命令的实体并不包含在shell中,但是其命令执行过程是由shell程序控制的。shell程序管理外部命令执行的路径查找、加载存放,并控制命令的执行。外部命令是在bash之外额外安装的,通常放在/bin,/usr/bin,/sbin,/usr/sbin......等等
Linux世界实际由fork(), exce族函数, wait()三个函数搭建。下面通过这三个函数编写一个myshell实现linux外部命令(来源于李慧芹老师讲解的基于LINUX的C语言课程。 )
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <glob.h>
#include <sys/wait.h>
#define DELIMS " \t\n"
struct cmd_st
{
glob_t globres;
};
static void prompt(void)
{
printf("mysh-0.1$ ");
}
static void parse(char *line, struct cmd_st *res)
{
char *tok;
int i = 0;
while(1)
{
tok = strsep(&line, DELIMS);
if(tok == NULL)
break;
if(tok[0] == '\0')
continue;
glob(tok, GLOB_NOCHECK | GLOB_APPEND * i, NULL, &res->globres);
i = 1;
}
}
int main()
{
char *linebuf = NULL;
size_t linebuf_size = 0;
struct cmd_st cmd;
while(1)
{
pid_t pid;
// 打印标识符
prompt();
// 从标准输入获取外部命令
if(getline(&linebuf, &linebuf_size, stdin) < 0)
break;
// 解析外部命令:拆分argv[]
parse(linebuf, &cmd);
if(0)
{
// 执行内部命令
printf("Internal command is not executed\n");
}
else
{
// 执行外部命令
pid = fork();
if( pid < 0)
{
perror("fork()");
exit(1);
}
if(pid == 0)
{
execvp(cmd.globres.gl_pathv[0], cmd.globres.gl_pathv);
perror("execvp()");
exit(1);
}
else
{
wait(NULL);
}
}
}
exit(0);
}