点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/select.h>
#define MAX_INPUT_LEN 1024
#define MAX_ARGS 64
#define READ_BUF_SIZE 4096
#define PIPE_READ 0
#define PIPE_WRITE 1
#define STDIN_FD STDIN_FILENO
#define STDOUT_FD STDOUT_FILENO
#define SELECT_ERROR (-1)
#define CHILD_PROCESS (0)
int split_input(char *line, char **args) {
int count = 0;
char *token = strtok(line, " \t\n");
while ((token != NULL) && (count < (MAX_ARGS - 1))) {
args[count] = token;
count++;
token = strtok(NULL, " \t\n");
}
args[count] = NULL;
return count;
}
int main() {
char input[MAX_INPUT_LEN] = {0};
char *args[MAX_ARGS] = {NULL};
while (1) {
printf("mysh> ");
fflush(stdout);
if (fgets(input, sizeof(input), stdin) == NULL) {
break;
}
input[strcspn(input, "\n")] = '\0';
if (strcmp(input, "exit") == 0) {
break;
}
int arg_count = split_input(input, args);
if (arg_count == 0) {
continue;
}
int pipefd[2] = {-1, -1};
if (pipe(pipefd) == -1) {
perror("pipe");
continue;
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
close(pipefd[PIPE_READ]);
close(pipefd[PIPE_WRITE]);
continue;
}
if (pid == CHILD_PROCESS) {
close(pipefd[PIPE_READ]);
dup2(pipefd[PIPE_WRITE], STDOUT_FD);
close(pipefd[PIPE_WRITE]);
execvp(args[0], args);
perror("execvp");
exit(EXIT_FAILURE);
} else {
close(pipefd[PIPE_WRITE]);
fd_set readfds;
int max_fd = (pipefd[PIPE_READ] > STDIN_FD) ?
(pipefd[PIPE_READ] + 1) :
(STDIN_FD + 1);
char buffer[READ_BUF_SIZE] = {0};
int stop_requested = 0;
while (1) {
FD_ZERO(&readfds);
FD_SET(pipefd[PIPE_READ], &readfds);
FD_SET(STDIN_FD, &readfds);
if (select(max_fd, &readfds, NULL, NULL, NULL) == SELECT_ERROR) {
perror("select");
break;
}
if (FD_ISSET(STDIN_FD, &readfds)) {
char cmd[MAX_INPUT_LEN] = {0};
if (fgets(cmd, sizeof(cmd), stdin) == NULL) {
break;
}
cmd[strcspn(cmd, "\n")] = '\0';
if (strcmp(cmd, "stop") == 0) {
kill(pid, SIGKILL);
waitpid(pid, NULL, 0);
stop_requested = 1;
printf("Command terminated by user.\n");
break;
}
}
if (FD_ISSET(pipefd[PIPE_READ], &readfds)) {
ssize_t bytes = read(pipefd[PIPE_READ], buffer, sizeof(buffer) - 1);
if (bytes <= 0) {
break;
}
buffer[bytes] = '\0';
printf("%s", buffer);
}
}
close(pipefd[PIPE_READ]);
if (!stop_requested) {
waitpid(pid, NULL, 0);
}
}
}
return EXIT_SUCCESS;
}
点击查看代码
/* mysh.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#define MAX_INPUT_LEN 1024
#define MAX_ARGS 64
#define READ_BUF_SIZE 4096
/* ---------- 工具函数 ---------- */
static void die(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
static int split_input(char *line, char **argv)
{
int argc = 0;
for (char *tok = strtok(line, " \t\n"); tok && argc < MAX_ARGS - 1; tok = strtok(NULL, " \t\n"))
argv[argc++] = tok;
argv[argc] = NULL;
return argc;
}
/* ---------- 子进程执行 ---------- */
static void run_child(char *const argv[])
{
execvp(argv[0], argv);
die("execvp");
}
/* ---------- 父进程读取/监控 ---------- */
static void relay_output_and_wait(int pipe_out, pid_t child)
{
fd_set rfds;
char buf[READ_BUF_SIZE];
int child_done = 0;
while (!child_done) {
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
FD_SET(pipe_out, &rfds);
int maxfd = (pipe_out > STDIN_FILENO ? pipe_out : STDIN_FILENO) + 1;
if (select(maxfd, &rfds, NULL, NULL, NULL) == -1) {
if (errno == EINTR) continue;
perror("select");
break;
}
/* 用户输入:仅处理 stop 命令 */
if (FD_ISSET(STDIN_FILENO, &rfds)) {
char line[MAX_INPUT_LEN];
if (!fgets(line, sizeof(line), stdin))
break;
if (strncmp(line, "stop", 4) == 0) {
kill(child, SIGKILL);
waitpid(child, NULL, 0);
puts("Command terminated by user.");
return;
}
}
/* 子进程输出 */
if (FD_ISSET(pipe_out, &rfds)) {
ssize_t n = read(pipe_out, buf, sizeof(buf) - 1);
if (n <= 0) {
child_done = 1;
} else {
buf[n] = '\0';
fputs(buf, stdout);
fflush(stdout);
}
}
}
/* 正常结束 */
close(pipe_out);
waitpid(child, NULL, 0);
}
/* ---------- 主循环 ---------- */
static void shell_loop(void)
{
char input[MAX_INPUT_LEN];
char *argv[MAX_ARGS];
while (1) {
printf("mysh> ");
fflush(stdout);
if (!fgets(input, sizeof(input), stdin)) /* EOF (Ctrl-D) */
break;
input[strcspn(input, "\n")] = '\0';
if (strcmp(input, "exit") == 0)
break;
int argc = split_input(input, argv);
if (argc == 0)
continue;
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
continue;
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
close(pipefd[0]);
close(pipefd[1]);
continue;
}
if (pid == 0) { /* child */
close(pipefd[0]); /* 关闭读端 */
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
run_child(argv);
} else { /* parent */
close(pipefd[1]); /* 关闭写端 */
relay_output_and_wait(pipefd[0], pid);
}
}
}
int main(void)
{
shell_loop();
return EXIT_SUCCESS;
}