点击查看代码
/** simple_shell.c* 简易 Shell:支持单条命令及其参数* - 输入 exit → Shell 自身退出* - 输入 stop → 终止当前正在运行的子进程* 编译:gcc -std=c11 -Wall -Wextra -pedantic simple_shell.c -o simple_shell*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>/*-------------------- 宏定义 --------------------*/
#define MAX_LINE_LEN 1024 /* 命令行最大长度 */
#define MAX_ARGS 64 /* 参数最大个数 *//*-------------------- 全局变量 ------------------*/
static pid_t g_child_pid = 0; /* 当前子进程 PID,若无则为 0 *//*-------------------- 工具函数 ------------------*/
static void die(const char *msg)
{perror(msg);exit(EXIT_FAILURE);
}/* 去掉行尾换行符 */
static void trim_newline(char *line)
{char *p = strchr(line, '\n');if (p) *p = '\0';
}/* 解析命令行到 argv 数组,返回参数个数 */
static size_t parse_line(char *line, char *argv[])
{size_t argc = 0;char *token = strtok(line, " ");while (token && argc < MAX_ARGS - 1) {argv[argc++] = token;token = strtok(NULL, " ");}argv[argc] = NULL;return argc;
}/*-------------------- 主函数 --------------------*/
int main(void)
{char line[MAX_LINE_LEN] = {0};char *argv[MAX_ARGS] = {NULL};pid_t pid = 0;int status = 0;for (;;) {/* 提示符 */printf("simple_shell$ ");fflush(stdout);/* 读取一行输入 */if (!fgets(line, sizeof(line), stdin)) {break; /* EOF (Ctrl-D) */}/* 去掉换行符 */trim_newline(line);/* 空行继续 */if (strlen(line) == 0) {continue;}/* 解析命令行 */size_t argc = parse_line(line, argv);/* 内置命令:exit */if (strcmp(argv[0], "exit") == 0) {break;}/* 内置命令:stop */if (strcmp(argv[0], "stop") == 0) {if (g_child_pid > 0) {(void)kill(g_child_pid, SIGTERM);}continue;}/* 创建子进程执行外部命令 */pid = fork();if (pid < 0) {die("fork");} else if (pid == 0) {/* 子进程 */execvp(argv[0], argv);die("execvp"); /* 仅当 execvp 失败时到达 */} else {/* 父进程记录子进程 PID 并等待其结束 */g_child_pid = pid;waitpid(pid, &status, 0);g_child_pid = 0; /* 子进程已结束,清零 */}}return 0;
}