什么是 Shell?常见的 Unix Shell有哪些?(中英双语)
看到一篇实现shell的tutorial,想动手实现一遍。先了解一下shell的来龙去脉。故有此文。
https://brennan.io/2015/01/16/write-a-shell-in-c/
中文版
什么是 Shell?
Shell 是计算机操作系统中的 命令解释器,充当用户和内核(Kernel)之间的接口,允许用户输入命令并执行系统操作。它既可以是一个 交互式 环境(用户输入命令,Shell 解析并执行),也可以是 脚本环境(执行 .sh
脚本文件)。
在 Unix 和 Linux 系统中,Shell 是一种 用户空间程序,它的主要作用包括:
- 命令解释:将用户输入的命令解析并执行。
- 进程管理:创建、终止、控制后台任务等。
- 输入输出管理:重定向 (
>
、<
)、管道 (|
) 等功能。 - 脚本执行:支持 Shell 脚本(如
.sh
文件),用于自动化任务。 - 环境管理:定义和管理环境变量,如
$PATH
。
什么是 Unix Shell?
Unix Shell 是指在 Unix 系统(包括 Linux、macOS、BSD 等)上运行的 Shell。它不仅支持命令行交互,还提供脚本编程能力。
常见的 Unix Shell
Unix 发展过程中,出现了多种 Shell 版本:
- Bourne Shell (
sh
):最早的 Unix Shell,由 AT&T Bell Labs 的 Stephen Bourne 在 1979 年发布。 - Bash (
bash
):GNU 项目的改进版 Bourne Again Shell,支持命令历史、补全等功能,是目前最流行的 Shell(Linux 默认 Shell)。 - C Shell (
csh
):类似 C 语言语法的 Shell,BSD Unix 早期流行。 - Korn Shell (
ksh
):由 David Korn 开发,结合了 Bourne Shell 和 C Shell 的优点,广泛用于商业 Unix 系统。 - Z Shell (
zsh
):扩展了 Bash,支持更强大的自动补全和插件系统,macOS 现默认使用它。
Shell 的实现
Unix Shell 的实现本质上是一个 用户态的 C 程序,主要完成:
- 读取用户输入(
read()
或fgets()
)。 - 解析输入命令(
strtok()
进行分词)。 - 查找命令的可执行文件(遍历
$PATH
目录,调用execvp()
)。 - 创建子进程执行命令(
fork()
+execve()
)。 - 等待子进程执行完成(
waitpid()
)。 - 显示提示符并循环执行(
while
循环)。
简化版 Shell 的代码实现
以下是一个 最小化 Shell 的 C 语言实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_INPUT_SIZE 1024
int main() {
char command[MAX_INPUT_SIZE];
while (1) {
printf("my_shell> ");
if (fgets(command, MAX_INPUT_SIZE, stdin) == NULL) {
break; // 处理 Ctrl+D 退出
}
command[strcspn(command, "\n")] = 0; // 去掉换行符
if (strcmp(command, "exit") == 0) break; // 退出 Shell
pid_t pid = fork();
if (pid == 0) { // 子进程执行命令
char *args[] = { "/bin/sh", "-c", command, NULL };
execvp(args[0], args);
exit(1); // 如果 exec 失败,则退出
} else { // 父进程等待子进程结束
wait(NULL);
}
}
return 0;
}
Shell 的关键系统调用
fork()
:创建子进程。execvp()
:在子进程中执行命令(搜索$PATH
路径)。waitpid()
:父进程等待子进程完成。read()
/fgets()
:获取用户输入。strtok()
:解析输入字符串。
Shell 的工作流程
以执行命令 ls -l
为例:
- Shell 显示提示符(
my_shell>
)。 - 用户输入命令(
ls -l
)。 - Shell 读取输入并解析(分解
ls
和-l
)。 - 创建子进程(
fork()
)。 - 子进程执行命令:
- 搜索可执行文件(遍历
$PATH
)。 - 调用
execvp("ls", ["ls", "-l"])
执行ls
命令。
- 搜索可执行文件(遍历
- 父进程等待子进程执行完毕(
waitpid()
)。 - Shell 显示新的提示符,等待下一次输入。
Shell 进阶功能
- 环境变量(
export VAR=value
):存储变量,影响 Shell 进程行为。 - 重定向(
>
、<
、>>
):输入输出文件操作。 - 管道(
|
):连接多个命令,如ls | grep txt
。 - 后台执行(
&
):sleep 10 &
后台运行进程。 - Shell 脚本(
#!/bin/bash
):编写自动化任务脚本。
总结
- Shell 是 Unix 的命令解释器,提供命令执行和脚本能力。
- Unix Shell 主要有 Bash、Zsh、Ksh 等,其中 Bash 是最常用的。
- Shell 本质是一个 C 程序,核心实现基于
fork()
和exec()
。 - Shell 支持命令解析、进程管理、输入输出重定向等高级功能。
Shell 作为 Unix/Linux 系统的核心组件,在系统管理、自动化运维、脚本编程等领域发挥着重要作用。
英文版
What is a Shell?
A Shell is a command-line interpreter that acts as an interface between the user and the operating system’s kernel. It allows users to execute commands, manage processes, and perform file operations. Shells can operate in interactive mode (where users type commands manually) or in script mode (executing .sh
files for automation).
In Unix and Linux systems, the Shell is a user-space program responsible for:
- Command interpretation: Parsing and executing user commands.
- Process management: Creating, terminating, and handling background tasks.
- Input/Output redirection: Handling redirections (
>
and<
) and pipes (|
). - Script execution: Running shell scripts for automation.
- Environment management: Setting environment variables like
$PATH
.
What is a Unix Shell?
A Unix Shell is a command-line interface (CLI) available in Unix-based operating systems like Linux, macOS, and BSD. It supports command execution and script programming.
Common Unix Shells
Several Shell implementations exist in Unix history:
- Bourne Shell (
sh
) – Developed in 1979 by Stephen Bourne at AT&T Bell Labs, forming the basis for many modern shells. - Bash (
bash
) – The GNU Project’s Bourne Again Shell, widely used today, offering features like command history and auto-completion. - C Shell (
csh
) – Designed with C-like syntax, popular in early BSD Unix versions. - Korn Shell (
ksh
) – Combines features of Bourne and C Shell, commonly used in commercial Unix. - Z Shell (
zsh
) – An extended Bash with better auto-completion and customization, now the default shell on macOS.
How is a Shell Implemented?
A Unix Shell is essentially a C program running in user space that performs the following tasks:
- Read user input (
read()
orfgets()
). - Parse the input (
strtok()
for tokenization). - Search for the executable command (iterating through
$PATH
and usingexecvp()
). - Create a child process to execute the command (
fork()
+execve()
). - Wait for the child process to complete (
waitpid()
). - Display a prompt and repeat the process (using a
while
loop).
Minimal Shell Implementation in C
Below is a simple Unix Shell written in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_INPUT_SIZE 1024
int main() {
char command[MAX_INPUT_SIZE];
while (1) {
printf("my_shell> ");
if (fgets(command, MAX_INPUT_SIZE, stdin) == NULL) {
break; // Handle Ctrl+D exit
}
command[strcspn(command, "\n")] = 0; // Remove newline character
if (strcmp(command, "exit") == 0) break; // Exit the shell
pid_t pid = fork();
if (pid == 0) { // Child process executes command
char *args[] = { "/bin/sh", "-c", command, NULL };
execvp(args[0], args);
exit(1); // Exit if exec fails
} else { // Parent process waits
wait(NULL);
}
}
return 0;
}
Key System Calls Used in Shell
fork()
– Creates a new child process.execvp()
– Replaces the child process with the new command execution.waitpid()
– The parent process waits for the child to finish.read()
/fgets()
– Reads user input from stdin.strtok()
– Tokenizes input for parsing.
Shell Execution Workflow
For a command like ls -l
, the Shell performs:
- Displays the prompt (
my_shell>
). - Reads user input (
ls -l
). - Parses the command (splitting
ls
and-l
). - Creates a child process (
fork()
). - Executes the command in the child process:
- Searches for the executable (
ls
in$PATH
). - Calls
execvp("ls", ["ls", "-l"])
.
- Searches for the executable (
- Parent process waits for completion (
waitpid()
). - Repeats the process for new commands.
Advanced Shell Features
- Environment Variables (
export VAR=value
) – Store variables affecting shell behavior. - Redirection (
>
<
>>
) – Redirecting input/output to files. - Pipes (
|
) – Connecting multiple commands (ls | grep txt
). - Background Execution (
&
) – Running tasks in the background (sleep 10 &
). - Shell Scripting (
#!/bin/bash
) – Automating tasks with scripts.
Summary
- Shell is a command-line interpreter that bridges users and the OS kernel.
- Unix Shells include Bash, Zsh, Ksh, etc., with Bash being the most common.
- A Shell is implemented as a user-space C program, utilizing
fork()
,execvp()
, andwaitpid()
. - Shells support command execution, process management, I/O redirection, scripting, and automation.
Shells play a crucial role in system administration, DevOps, and automation, making them an essential tool in Unix-based operating systems.
后记
2025年2月3日于山东日照。在GPT4o大模型辅助下完成。