exit(1) builtin command

本文深入讲解了Shell内置命令exit的功能,包括其基本介绍、命令格式和常见应用场景,如从终端或脚本中退出Shell进程,并介绍了如何通过状态码判断退出是否正常。


大咖好呀,我是恋喵大鲤鱼。

!!! 我的第二本开源书籍《后台开发命令365》上线啦,欢迎大家协同共建。

1.命令简介

exit 是 Shell 内建命令,用于退出当前 Shell 进程。

2.命令格式

exit N

(1)状态码 N 的范围是 0-255,一般情况下,0 表示正常退出,非零表示异常退出。如果是 0-255 之外的数值,则会被强制转换为 uint8_t 类型的数值,比如 -1 会被转换为 255,256 会发生类型宽度截断,被转换为 0;

(2)状态码 N 可以不指定,默认是上一条命令的退出状态码。

3.常用示例

(1)退出终端。

exit

(2)用于Shell脚本,退出当前Shell进程。

#正常结果
exit 0

#异常退出
exit 1

(3)使用 trap 内建命令,用于挂载 Shell 进程结束前需要执行的命令。格式为:trap “commands” EXIT。如脚本exit.sh:

#!/bin/bash

echo "start"
trap "echo 'end'" EXIT
echo "before exit"
exit 0

执行exit.sh输出:

start
before exit
end

参考文献

exit(1) - Linux manual page - linux.org

#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); } }根据问题修改
最新发布
09-10
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值