本次写个简单的Shell进程玩玩!!!
用前面所学的知识写一个简单的Shell
[lyh_sky@localhost myshell]$ cat myshell.c
#include
#include
#include
#include
#include
#include
#include
#define NUM 1024
#define SIZE 128
#define SEP " "
char command_line[NUM];
char* command_args[SIZE];
char env_buffer[NUM];
extern char** environ;
int ChangDIR(const char* new_path)
{
chdir(new_path);
return 1; // 调用成功返回1
}
void PutEnvInMyVM(char* new_env)
{
putenv(new_env);
}
int main()
{
struct passwd* pwd = getpwuid(getuid());
// shell是一个进程,他本质是一个死循环
while (1)
{
// 1、显示基本的提示符:[用户名@主机名 当前目录]#/$
printf("[%s@localhost myshell]# ", pwd->pw_name);
fflush(stdout);
// 2、获取用户输入
memset(command_line, '\0', sizeof(char) * NUM);
fgets(command_line, NUM, stdin);
command_line[strlen(command_line) - 1] = '\0'; // 清空\n,fgets在输入完成后,也会读取回车换行
// 3、字符串切分 "ls -a -l" -- "ls", "-a", "-l", 使用strtok函数进行切割
command_args[0] = strtok(command_line, SEP);
int index = 1;
// ls添加语法高亮
if (strcmp(command_args[0], "ls") == 0)
{
command_args[1] = (char*)"--color=auto";
index = 2;
}
while (command_args[index++] = strtok(NULL, SEP))
{}
// 内建命令,cd指令不能在子进程中运行,因为子进程运行后不会回馈给父进程(执行完就释放了)
if (strcmp(command_args[0], "cd") == 0 && command_args[1] != NULL)
{
ChangDIR(command_args[1]);
continue; // shell内建命令,执行完重新回到开始然后继续执行...
}
if (strcmp(command_args[0], "export") == 0 && command_args[1] != NULL)
{
// 新的环境变量被保存在command_line中,第二次会被memset清空
// putenv创建环境变量,必须在本进程的上下文中有效
strcpy(env_buffer, command_args[1]);
PutEnvInMyVM(env_buffer);
}
pid_t id = fork();
if (id == 0)
{
// 子进程
execvp(command_args[0], command_args);
exit(0);
}
else if (id > 0)
{
// 父进程
int status = 0;
pid_t ret = waitpid(id, &status, 0); // 非阻塞等待
if (ret > 0)
{
printf("父进程等待成功, sig: %d, code: %d\n", status&0x7F, (status>>8)&0xFF);
}
else if (ret == 0)
{
printf("子进程还没有退出,继续等待!!!\n");
}
else if (ret < 0)
{
printf("等待失败!!!\n");
}
}
}
return 0;
}