#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <errno.h>
#define MAX_INPUT_LENGTH 1024
#define MAX_ARG_COUNT 64
#define MAX_PIPE_COUNT 10
// 颜色定义
#define COLOR_RESET "\033[0m"
#define COLOR_BLUE "\033[1;34m" // 目录
#define COLOR_GREEN "\033[1;32m" // 可执行文件
#define COLOR_RED "\033[1;31m" // 压缩文件
#define COLOR_CYAN "\033[1;36m" // 符号链接
#define COLOR_YELLOW "\033[1;33m" // 设备文件
// 函数声明
void print_prompt();
void read_input(char *input);
int parse_input(char *input, char **args, int *input_redirect, int *output_redirect,
char *input_file, char *output_file, int *append);
void execute_command(char **args, int input_redirect, int output_redirect,
char *input_file, char *output_file, int append);
int is_builtin_command(char **args);
void execute_builtin_command(char **args);
void help_command();
void cd_command(char **args);
void pwd_command();
void echo_command(char **args);
void ls_command(char **args);
void print_file_info(const char *path, const char *filename, int long_format);
void print_permissions(mode_t mode);
void print_color_by_type(mode_t mode);
void touch_command(char **args);
void mkdir_command(char **args);
void rm_command(char **args);
void rmdir_command(char **args);
void cat_command(char **args);
void cp_command(char **args);
void mv_command(char **args);
int parse_pipeline(char *input, char ***commands, int *num_commands);
void execute_pipeline(char ***commands, int num_commands);
int main() {
char input[MAX_INPUT_LENGTH];
char *args[MAX_ARG_COUNT];
int input_redirect, output_redirect, append;
char input_file[MAX_INPUT_LENGTH], output_file[MAX_INPUT_LENGTH];
while (1) {
print_prompt();
read_input(input);
if (strlen(input) == 0) {
continue;
}
// 检查管道命令
char *pipeline_commands[MAX_PIPE_COUNT][MAX_ARG_COUNT];
int num_commands = 0;
if (parse_pipeline(input, pipeline_commands, &num_commands)) {
execute_pipeline(pipeline_commands, num_commands);
continue;
}
// 解析普通命令
int arg_count = parse_input(input, args, &input_redirect, &output_redirect,
input_file, output_file, &append);
if (arg_count == 0) {
continue;
}
if (is_builtin_command(args)) {
execute_builtin_command(args);
} else {
execute_command(args, input_redirect, output_redirect,
input_file, output_file, append);
}
}
return 0;
}
void print_prompt() {
char cwd[MAX_INPUT_LENGTH];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
printf("%s$ ", cwd);
} else {
printf("myshell$ ");
}
fflush(stdout);
}
void read_input(char *input) {
if (fgets(input, MAX_INPUT_LENGTH, stdin) == NULL) {
if (feof(stdin)) {
printf("\n");
exit(0);
} else {
perror("fgets");
exit(1);
}
}
// 移除换行符
input[strcspn(input, "\n")] = '\0';
}
int parse_input(char *input, char **args, int *input_redirect, int *output_redirect,
char *input_file, char *output_file, int *append) {
*input_redirect = 0;
*output_redirect = 0;
*append = 0;
input_file[0] = '\0';
output_file[0] = '\0';
int arg_count = 0;
char *token = strtok(input, " \t");
while (token != NULL) {
if (strcmp(token, "<") == 0) {
*input_redirect = 1;
token = strtok(NULL, " \t");
if (token != NULL) {
strcpy(input_file, token);
}
} else if (strcmp(token, ">") == 0) {
*output_redirect = 1;
token = strtok(NULL, " \t");
if (token != NULL) {
strcpy(output_file, token);
}
} else if (strcmp(token, ">>") == 0) {
*output_redirect = 1;
*append = 1;
token = strtok(NULL, " \t");
if (token != NULL) {
strcpy(output_file, token);
}
} else {
args[arg_count++] = token;
}
token = strtok(NULL, " \t");
}
args[arg_count] = NULL;
return arg_count;
}
void execute_command(char **args, int input_redirect, int output_redirect,
char *input_file, char *output_file, int append) {
pid_t pid = fork();
if (pid == 0) {
// 子进程
if (input_redirect) {
int fd = open(input_file, O_RDONLY);
if (fd < 0) {
perror("open");
exit(1);
}
dup2(fd, STDIN_FILENO);
close(fd);
}
if (output_redirect) {
int flags = O_WRONLY | O_CREAT;
if (append) {
flags |= O_APPEND;
} else {
flags |= O_TRUNC;
}
int fd = open(output_file, flags, 0644);
if (fd < 0) {
perror("open");
exit(1);
}
dup2(fd, STDOUT_FILENO);
close(fd);
}
execvp(args[0], args);
perror("execvp");
exit(1);
} else if (pid > 0) {
// 父进程
int status;
waitpid(pid, &status, 0);
} else {
perror("fork");
}
}
int is_builtin_command(char **args) {
if (args[0] == NULL) {
return 0;
}
char *builtin_commands[] = {
"help", "cd", "pwd", "echo", "ls", "touch", "mkdir",
"rm", "rmdir", "cat", "cp", "mv", "quit", NULL
};
for (int i = 0; builtin_commands[i] != NULL; i++) {
if (strcmp(args[0], builtin_commands[i]) == 0) {
return 1;
}
}
return 0;
}
void execute_builtin_command(char **args) {
if (strcmp(args[0], "help") == 0) {
help_command();
} else if (strcmp(args[0], "cd") == 0) {
cd_command(args);
} else if (strcmp(args[0], "pwd") == 0) {
pwd_command();
} else if (strcmp(args[0], "echo") == 0) {
echo_command(args);
} else if (strcmp(args[0], "ls") == 0) {
ls_command(args);
} else if (strcmp(args[0], "touch") == 0) {
touch_command(args);
} else if (strcmp(args[0], "mkdir") == 0) {
mkdir_command(args);
} else if (strcmp(args[0], "rm") == 0) {
rm_command(args);
} else if (strcmp(args[0], "rmdir") == 0) {
rmdir_command(args);
} else if (strcmp(args[0], "cat") == 0) {
cat_command(args);
} else if (strcmp(args[0], "cp") == 0) {
cp_command(args);
} else if (strcmp(args[0], "mv") == 0) {
mv_command(args);
} else if (strcmp(args[0], "quit") == 0) {
exit(0);
}
}
void help_command() {
printf("MyShell - 支持的命令:\n");
printf(" help 显示所有支持的命令\n");
printf(" cd [directory] 改变当前工作目录\n");
printf(" pwd 显示当前工作目录\n");
printf(" ls [options] [dir] 列出目录内容\n");
printf(" echo [text] 显示文本\n");
printf(" touch <file> 创建空文件\n");
printf(" mkdir <dir> 创建目录\n");
printf(" rm <file> 删除文件\n");
printf(" rmdir <dir> 删除空目录\n");
printf(" cat <file> 显示文件内容\n");
printf(" cp <src> <dest> 复制文件\n");
printf(" mv <src> <dest> 移动文件/重命名\n");
printf(" quit 退出shell\n");
printf("\n");
printf("I/O 重定向:\n");
printf(" command < file 输入重定向\n");
printf(" command > file 输出重定向(覆盖)\n");
printf(" command >> file 输出重定向(追加)\n");
printf("\n");
printf("管道操作:\n");
printf(" command1 | command2 将command1的输出作为command2的输入\n");
}
void cd_command(char **args) {
if (args[1] == NULL) {
chdir(getenv("HOME"));
} else {
if (chdir(args[1]) != 0) {
perror("cd");
}
}
}
void pwd_command() {
char cwd[MAX_INPUT_LENGTH];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
printf("%s\n", cwd);
} else {
perror("pwd");
}
}
void echo_command(char **args) {
for (int i = 1; args[i] != NULL; i++) {
printf("%s ", args[i]);
}
printf("\n");
}
void ls_command(char **args) {
int long_format = 0;
int show_all = 0;
int recursive = 0;
char *dir_path = ".";
// 解析参数
for (int i = 1; args[i] != NULL; i++) {
if (args[i][0] == '-') {
for (int j = 1; args[i][j] != '\0'; j++) {
switch (args[i][j]) {
case 'l': long_format = 1; break;
case 'a': show_all = 1; break;
case 'R': recursive = 1; break;
default:
printf("ls: invalid option -- '%c'\n", args[i][j]);
return;
}
}
} else {
dir_path = args[i];
}
}
DIR *dir = opendir(dir_path);
if (dir == NULL) {
perror("ls");
return;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (!show_all && entry->d_name[0] == '.') {
continue;
}
char full_path[MAX_INPUT_LENGTH];
snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name);
if (long_format) {
print_file_info(full_path, entry->d_name, long_format);
} else {
print_color_by_type(entry->d_type);
printf("%s", entry->d_name);
printf(COLOR_RESET " ");
}
}
if (!long_format) {
printf("\n");
}
closedir(dir);
}
void print_file_info(const char *path, const char *filename, int long_format) {
struct stat statbuf;
if (stat(path, &statbuf) == -1) {
perror("stat");
return;
}
// 文件类型和权限
print_permissions(statbuf.st_mode);
// 硬链接数
printf("%2ld ", statbuf.st_nlink);
// 所有者和组
struct passwd *pw = getpwuid(statbuf.st_uid);
struct group *gr = getgrgid(statbuf.st_gid);
printf("%s %s ", pw->pw_name, gr->gr_name);
// 文件大小
printf("%6ld ", statbuf.st_size);
// 修改时间
char timebuf[80];
struct tm *tm_info = localtime(&statbuf.st_mtime);
strftime(timebuf, sizeof(timebuf), "%b %d %H:%M", tm_info);
printf("%s ", timebuf);
// 文件名(带颜色)
print_color_by_type(statbuf.st_mode);
printf("%s", filename);
printf(COLOR_RESET "\n");
}
void print_permissions(mode_t mode) {
printf((S_ISDIR(mode)) ? "d" : "-");
printf((mode & S_IRUSR) ? "r" : "-");
printf((mode & S_IWUSR) ? "w" : "-");
printf((mode & S_IXUSR) ? "x" : "-");
printf((mode & S_IRGRP) ? "r" : "-");
printf((mode & S_IWGRP) ? "w" : "-");
printf((mode & S_IXGRP) ? "x" : "-");
printf((mode & S_IROTH) ? "r" : "-");
printf((mode & S_IWOTH) ? "w" : "-");
printf((mode & S_IXOTH) ? "x" : "-");
printf(" ");
}
void print_color_by_type(mode_t mode) {
if (S_ISDIR(mode)) {
printf(COLOR_BLUE); // 目录 - 蓝色
} else if (mode & S_IXUSR) {
printf(COLOR_GREEN); // 可执行文件 - 绿色
} else {
printf(COLOR_RESET); // 普通文件 - 默认颜色
}
}
void touch_command(char **args) {
if (args[1] == NULL) {
printf("touch: missing file operand\n");
return;
}
for (int i = 1; args[i] != NULL; i++) {
FILE *file = fopen(args[i], "a");
if (file == NULL) {
perror("touch");
} else {
fclose(file);
}
}
}
void mkdir_command(char **args) {
if (args[1] == NULL) {
printf("mkdir: missing operand\n");
return;
}
for (int i = 1; args[i] != NULL; i++) {
if (mkdir(args[i], 0755) != 0) {
perror("mkdir");
}
}
}
void rm_command(char **args) {
if (args[1] == NULL) {
printf("rm: missing operand\n");
return;
}
for (int i = 1; args[i] != NULL; i++) {
if (remove(args[i]) != 0) {
perror("rm");
}
}
}
void rmdir_command(char **args) {
if (args[1] == NULL) {
printf("rmdir: missing operand\n");
return;
}
for (int i = 1; args[i] != NULL; i++) {
if (rmdir(args[i]) != 0) {
perror("rmdir");
}
}
}
void cat_command(char **args) {
if (args[1] == NULL) {
printf("cat: missing file operand\n");
return;
}
for (int i = 1; args[i] != NULL; i++) {
FILE *file = fopen(args[i], "r");
if (file == NULL) {
perror("cat");
continue;
}
char buffer[1024];
while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer);
}
fclose(file);
}
}
void cp_command(char **args) {
if (args[1] == NULL || args[2] == NULL) {
printf("cp: missing file operand\n");
return;
}
FILE *src = fopen(args[1], "r");
if (src == NULL) {
perror("cp");
return;
}
FILE *dest = fopen(args[2], "w");
if (dest == NULL) {
perror("cp");
fclose(src);
return;
}
char buffer[1024];
size_t bytes;
while ((bytes = fread(buffer, 1, sizeof(buffer), src)) > 0) {
fwrite(buffer, 1, bytes, dest);
}
fclose(src);
fclose(dest);
}
void mv_command(char **args) {
if (args[1] == NULL || args[2] == NULL) {
printf("mv: missing file operand\n");
return;
}
if (rename(args[1], args[2]) != 0) {
perror("mv");
}
}
int parse_pipeline(char *input, char ***commands, int *num_commands) {
char *token = strtok(input, "|");
*num_commands = 0;
while (token != NULL && *num_commands < MAX_PIPE_COUNT) {
// 去除首尾空格
while (*token == ' ') token++;
char *end = token + strlen(token) - 1;
while (end > token && *end == ' ') end--;
*(end + 1) = '\0';
// 解析单个命令的参数
int arg_count = 0;
char *arg_token = strtok(token, " \t");
while (arg_token != NULL && arg_count < MAX_ARG_COUNT - 1) {
commands[*num_commands][arg_count++] = arg_token;
arg_token = strtok(NULL, " \t");
}
commands[*num_commands][arg_count] = NULL;
(*num_commands)++;
token = strtok(NULL, "|");
}
return (*num_commands > 1);
}
void execute_pipeline(char ***commands, int num_commands) {
int pipes[num_commands - 1][2];
pid_t pids[num_commands];
// 创建管道
for (int i = 0; i < num_commands - 1; i++) {
if (pipe(pipes[i]) == -1) {
perror("pipe");
return;
}
}
// 创建子进程
for (int i = 0; i < num_commands; i++) {
pids[i] = fork();
if (pids[i] == 0) {
// 子进程
// 设置输入
if (i > 0) {
dup2(pipes[i-1][0], STDIN_FILENO);
}
// 设置输出
if (i < num_commands - 1) {
dup2(pipes[i][1], STDOUT_FILENO);
}
// 关闭所有管道端
for (int j = 0; j < num_commands - 1; j++) {
close(pipes[j][0]);
close(pipes[j][1]);
}
// 执行命令
if (is_builtin_command(commands[i])) {
execute_builtin_command(commands[i]);
exit(0);
} else {
execvp(commands[i][0], commands[i]);
perror("execvp");
exit(1);
}
}
}
// 父进程关闭所有管道端
for (int i = 0; i < num_commands - 1; i++) {
close(pipes[i][0]);
close(pipes[i][1]);
}
// 等待所有子进程完成
for (int i = 0; i < num_commands; i++) {
waitpid(pids[i], NULL, 0);
}
}根据问题修改
最新发布