Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/celestialphineas/myshell
Example of a feature-rich (toy) Linux shell without control flow support.
https://github.com/celestialphineas/myshell
linux myshell shell toy-project unix
Last synced: about 2 months ago
JSON representation
Example of a feature-rich (toy) Linux shell without control flow support.
- Host: GitHub
- URL: https://github.com/celestialphineas/myshell
- Owner: celestialphineas
- License: mit
- Created: 2017-07-18T08:13:34.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2017-07-31T08:06:43.000Z (over 7 years ago)
- Last Synced: 2023-10-20T05:18:29.769Z (about 1 year ago)
- Topics: linux, myshell, shell, toy-project, unix
- Language: C
- Homepage:
- Size: 240 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: readme
- License: LICENSE
Awesome Lists containing this project
README
myshell 自述文档
===============version 0.1.0 \
Author: Celestial Phineas @ ZJU (Yehang YIN) \
Contact: yehangyin AT outlook DOT com \
License: MIT*该文档使用了Markdown语法。*
本文系 myshell 中文用户手册,如果您需要获知本项目的整体说明,请参阅 readme.md。
This file is the user's manual for myshell in simplified Chinese. See readme.md
for a more general perspective and a few details of implementation, as well as
a list of references.概述
----myshell 是一个 Linux 上的命令行 shell 实现,设计初衷是实现不含控制流的 bash 的一个子集。
shell 中文一般译为“壳层”,是用户访问操作系统的界面。称作“壳层”的原因是它提供了系统内核之上的
一层,可与用户交互。bash的全称是 Bourne-Again SHell,最早的作者是 Brain Fox,具有完备的
通配符匹配、管道、重定向、命令替换、变量替换、控制流和任务控制等功能。myshell 最终达成了上述
功能的部分。myshell 具有如下主要特性:
- 管道、重定向
- 变量设置与替换
- 相当一部分 shell 展开
- 波浪线展开(解释 home `~`)
- 变量展开
- 数组
- 数组元素
- 字符串长度
- 任务控制
- 内建命令
- 完善的命令提示符机制
- 支持 shebang 的处理
- ……myshell 不支持的主要特性:
- 命令替换 $()
- 子壳 (subshell,即圆括号)
- 控制流(if, while, for)
- shell 级的通配符展开(*和?的匹配)myshell 不支持或没有做过充足测试的次要特性:
- 本地化,甚至不做汉化
- Unicode 支持
- ANSI-C 转义字符展开 $''
- 历史命令
- 光标移动构建
----myshell 使用 make 工具构建,您只需要在 myshell 目录下键入命令 `make` 即可编译。
```
username@hostname:~/path/myshell$ make
```make 会自动完成编译过程。
运行
----在命令行中键入 myshell 可以交互模式运行 myshell。myshell 支持如下参数:
```
myshell
Usage: myshell [options] script ...
GNU options:
--help Show this help file
--version Show version
Shell options:
-i Run in interactive mode
```将脚本文件作为参数传入即可令 myshell 运行脚本,脚本文件名后面的参数将被视作脚本的参数传入,可
在脚本中用 $1 ~ $9 ~ ${10} ... 访问。myshell 支持对 shebang 的处理,也就是说您可以在终端中直接运行脚本,如果脚本的第一行指定了
myshell 的完整路径,myshell 即可正确处理脚本的打开与运行。shebang 指脚本文件头出现的“#!”
字符序列,其对应的二进制为 Unix 下约定的脚本文件魔数。在执行脚本文件时,会将该行剩余内容作为
执行这一脚本文件的命令。下面是一些例子,命令提示符用“$”表示:
```
$ ./myshell
username@hostname:pwd/
myshell>
``````
$ ./myshell script.sh
<运行脚本…>
``````
$ cat script.sh
#! ./myshell
echo hello world
$ chmod 777 script.sh
$ ./script
<运行脚本…>
```基本使用
--------经过成功编译与运行,myshell 已经可以开始使用了。终端中打印出的彩色字符是 myshell 的命令提示
符,您可以看到自己的用户名、计算机名和当前操作目录。myshell 的命令提示符尽可能与 bash 相一
致,但是为了彰示区别,命令提示符去掉了“$”符号,另起一行输出紫色 `myshell>`。### Hello world
下面一个例子将演示您如何在 myshell 中打印“Hello world”。您只需输入命令 `echo Hello world`
```
username@hostname:~/myshell
myshell> echo Hello world
```### 调用其他命令
您可以尝试键入 `ls`、`ps` 和 `pwd` 看看会发生什么。
### 清屏
清屏的命令是 `clear`,尝试一下。你会发现终端的文本内容清空了或上滚了一屏(取决于您所使用图形终
端的特性)。重定向
--------myshell 支持重定向。重定向可以将当前命令的输入或输出从终端定位到其他文件。在 Unix/Linux 中,
所有输入输出设备都被视作文件,文件也可以用于输入输出。将键盘输入和屏幕输出重定向到其他文件中当
然也是可行的。### 向一个文件写 Hello world
尝试一下这个命令:`echo hello world >hello.txt`,它会创建一个名为 `hello.txt` 的文件并
向其中写入 “hello world”。### 向文件中追加
对上面的例子做一个小小的修改:`echo hello world >>hello.txt`,看看会得到什么。
### 从文件中输入
完成上面两个例子,我们可以试试 `cat /dev/null` 则会打印出一条警告信息:
`WARNING: apt does not have a stable CLI interface. Use with caution in scripts.`
上面的命令中,`1` 的含义是文件描述符为 1 的文件,即标准输出。
`apt-get` 在运行时会检查当前输出是否为终端,如果不是则会发出这条警告,因为它有运行时中断的风
险。这样的警告在使用管道重定向 `apt-get` 时尤为常见。命令中的 `/dev/null` 俗称为黑洞,是
Linux 的一个空设备,没有任何反馈。如果我们尝试 `apt moo 1>/dev/null 2>/dev/null` 这条命令,整条命令会变得彻底悄无声息。
我们还可以交换标准输出和标准错误文件,这样我们同样会得到 `apt-get` 的报错,但是报错会写到标准
输出而不是标准错误上。命令为 `apt moo 2>&1 1>&2`。上面的例子都在 myshell 上测试通过了。
管道
----管道即将一个命令的输出作为下一个命令的输入。管道使用连接符 `|`。
您可以尝试下面这个命令:`gerp --help | more`,它将 `grep` 的帮助信息输出到 `more` 程序
的输入,使得您可以用浏览的方式查看该帮助文档。或者是 `ls | cat`,这个命令可以列出当前目录的所有文件并列出。
环境变量
--------在使用 shell 时,您会有一个当前操作目录(current working directory),所有相对路径都会由系
统在这个当前操作目录查找。### 打印当前操作目录
我们可以在命令提示符处看到当前操作目录,除此之外,还有可以使用 myshell 命令打印当前操作目录。
打印当前操作目录有两种方式,myshell 提供了一个名为 `pwd` 的内建命令用于打印当前操作目录。您只
需要输入 `pwd` 即可。myshell 提供了环境变量的替换,这意味着您同样可以使用 `${PWD}` 或 `$PWD` 得到当前目录。试试
`echo $PWD` 或 `echo ${PWD}`。### 改变当前操作目录
改变当前目录可以使用内建命令 `cd` (change directory),您只需在 `cd` 后面加上要转到的目录
路径就行了。当 `cd` 命令没有参数的时候,会默认改变当前目录到 `$HOME`(你可以试试 `echo $HOME`
看看会打印出什么)。特别地,`cd ..` 可以跳转到上一级目录,这是 Unix/Linux 系统的一个特性。
### 打印所有环境变量
大多数 Linux 发行版都提供了 `env` 程序,可以打印当前程序的所有环境变量。myshell 不提供导出
功能(不支持 export),也同样不覆写系统提供的 `env`,在 myshell 中输出的是原封不动的程序运
行环境。但是 myshell 加赠了一个环境变量称作 `PARENT` 其值即 myshell 的程序位置。### 变量的定义与替换
myshell 支持常见的变量定义方式,并提供变量替换的功能。例如,`$@` 会输出当前正在运行的
myshell 的所有参数,`$#` 则会输出参数的数目。具体到变量可以使用 `${#var[@]}` 访问到名字为
`var` 的数组中的元素个数。`${#var}` 则是这个数组第 0 个元素的字符串长度(变量皆视作长度为 1
的数组,在绝大多数 shell 实现中,变量都被统一处理成字符串数组,字符串是唯一存在的东西)。
访问变量的值我们刚刚已经接触过了,花括号加与不加在大多数情况中作用是一致的。不加花括号时,变量
扩展将会按照贪婪的方式向后匹配字符,直至遇到不合法的变量名字符和符号 (token) 末尾为止。两者
区别最显著之处在于 `$10` 和 `${10}` 是不一样的,前者只会替换 `$1`,而保留 `0` 作为字符,
后者会将 `10` 视作一个整体去进行替换。变量的定义使用 `=`,需要注意的是,变量名与等号之间是不能有空白字符的。等号的右侧可以为任何字符
串,如果右边的串不加引号的话,会匹配到空白字符为止。数组的定义使用 `var=(arg1 arg2 arg3)` 的形式,参数与参数之间使用空格隔开。
当前程序参数的更改可以使用内建的 `set` 命令。myshell 只实现 `set` 的无选项子集。命令
`set arg1 arg2 arg3` 会将 `$1`、`$2` 和 `$3` 分别设置为 `arg1`、`arg2` 和 `arg3`。尝试如下会话:
```
$ set arg1 arg2 arg3
$ echo $@
./myshell arg1 arg2 arg3
```如果想避免诸如 `${10}` 的变量访问方式,您可以使用 `shift` 命令将参数向前移一位,接续上面的会
话:```
$ shift
$ echo $@
arg1 arg2 arg3
```以上特性均在 myshell 上测试通过。
任务控制
--------myshell 支持任务控制,目前似乎还存在一些小问题。与 bash 任务控制不同的是,myshell 就是以任
务为中心的,每个输入命令都对应于一个任务。编号原则与实现方式也和 bash 有所不同,myshell 中任
务的编号是从开始运行之后顺次向下编的,第一条命令对应于任务 0,第二条对应于任务 1,依次类推。### 创建后台任务
创建后台任务在命令后加 `&` 即可。
与 bash 行为不同,myshell 不将 `&` 视作分割后台任务的字符,而视作连接后台进程流水线的连接
符。`sleep 10 & sleep 10 &` 将创建一个后台任务,这个后台任务的进程流水线拥有两个进程,每个
都是等待 10 秒钟的操作。### 查看所有任务
`jobs` 是一个内建命令,可以列出所有任务的任务号、完成状态和对应命令。你或许会看到 `jobs` 这个
任务本身也赫然在列,这是由于 myshell 和 bash 的任务控制机制不同所致。### 切换前台后台任务
前台任务和后台任务的区别在于是否占据终端的输入输出。myshell 中,您可以改变任务的前台后台状态。
一般地,没有被创建为后台任务的命令会被自动创建为前台任务,前台任务中您可以使用 `Ctrl + Z` 发
送停止信号,使任务被挂起。使用 `jobs` 可以列出任务,包括被挂起的任务,`fg [任务号]` 可以将任务重新放回前台
`bg [任务号]` 则会对任务中的进程发送继续信号,让进程继续。写在最后
--------如果您要写一个实用的 shell,绝大多数建议都是不要这样做,因为已经有很多足够好的解决方案,且有
很多比 shell 好的解决方案,可以让 shell 少承担一些负担,比如各种脚本语言。虽说如此,自己写一
个 shell 会极大提升对 Unix 和 Linux 的认知。这一文档以使用说明为主,有很多地方会流露出自己在编写过程中对 shell 的理解,希望这一文档,连同
这一项目的其他文档和源代码会对您有所启发。