一、shell是什么
Linux严格意义上说的是一个操作系统,我们称之为“核心(kernel)“ ,但我们一般用户,不能直接使用kernel。而是通过kernel的“外壳”程序,也就是所谓的shell,来与kernel沟通。
Shell的最简单定义:命令行解释器(command Interpreter)主要包含:
- 将使用者的命令翻译给核心(kernel)处理。
- 同时,将核心的处理结果翻译给使用者。
二、简单shell程序编写
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#define SIZE 64
#define NUM 1024
#define SEP " "
int lastcode = 0;
char* homepath()
{
char* home = getenv("HOME");
if(home)
return home;
else
return (char*)".";
}
const char* get_user_name()
{
const char* name = getenv("USER");
if(name)
return name;
else
return "none";
}
const char* get_host_name()
{
const char* hostname = getenv("HOSTNAME");
if(hostname)
return hostname;
else
return "none";
}
const char* get_pwd()
{
const char* pwd = getenv("PWD");
if(pwd)
return pwd;
else
return "none";
}
int get_user_command(char* command, int num)
{
printf("[%s@%s %s]# ", get_user_name(), get_host_name(), get_pwd());
//获取命令行
char* ret = fgets(command,num,stdin);//无论输入什么,最后一定会输入'\n'(回车)
command[strlen(command) - 1] = '\0';//所以我们将该命令行数组的最后一个元素改为'\0',不会越界
if(ret == NULL)
{
return -1;
}
return strlen(command);
}
void command_split(char* in, char* out[])
{
int argc = 0;
//2. 分割字符串
out[argc] = strtok(in, SEP);
while(out[argc++])
{
out[argc] = strtok(NULL,SEP);
}
//测试
// for(int i = 0; out[i]; i++)
// {
// printf("%d: %s\n", i, out[i]);
// }
}
int excute(char* argv[])
{
//4. 执行命令
pid_t id = fork();
{
if(id < 0)
{
return -1;
}
else if(id == 0)
{
//子进程执行command
execvp(argv[0],argv);
//执行完毕后退出
exit(1);
}
else
{
//父进程等待子进程
int status = 0;
pid_t rid = waitpid(id, &status, 0);
if(rid > 0)
{
lastcode = WEXITSTATUS(status);
}
}
}
return 0;
}
char pwd[1024];
void cd(const char* path)
{
char tmp[1024];
chdir(path);
getcwd(tmp,sizeof tmp);
sprintf(pwd, "PWD=%s",tmp);
putenv(pwd);
}
char myenv[10][100];//10条环境变量,一条容量为100
int v = 0;
//內键命令: 由bash自己执行,类似于自己内部的一个函数
int is_build_in(char* argv[])
{
if(strcmp(argv[0], "cd") == 0)
{
char* path = NULL;
if(argv[1] == NULL)
path = homepath();
else
path = argv[1];
cd(path);
return 1;
}
else if(strcmp(argv[0], "export") == 0)
{
if(argv[1] == NULL)
return 1;
else
{
strcpy(myenv[v++],argv[1]);
putenv(myenv[v-1]);
}
}
else if(strcmp(argv[0], "echo") == 0)
{
if(argv[1] == NULL)
{
printf("\n");
return 1;
}
if(*(argv[1]) == '$')
{
char* val = argv[1]+1;
if(strcmp(val,"?" ) == 0)
{
printf("%d\n",lastcode);
lastcode = 0;
}
else
{
const char* enval = getenv(val);
if(enval)
printf("%s\n",enval);
else
printf("\n");
}
return 1;
}
else
{
printf("%s\n",argv[1]);
return 1;
}
}
return 0;
}
int main()
{
while(1)
{
lastcode = 0;
char user_command_line[NUM];
char* argv[SIZE] = {NULL};
//1. 打印提示符&&获取用户命令字符串
int n = get_user_command(user_command_line,sizeof(user_command_line));
if(n <= 0)
continue;
//2. 分割字符串
command_split(user_command_line, argv);
//3. 检查是否为內键命令
n = is_build_in(argv);
if(n)
continue;
//4. 执行命令
excute(argv);
}
return 0;
}
三、makefile文件
mybash:myshell.c
gcc -o $@ $^ -std=c99
.PHONY:clean
clean:
rm -f mybash