命令行 x
shell v
其实shell的教程有很多, 随便找一篇跟着学就好(
senioria打算在这里给一下"构造"shell的思路.
senioria之前跟tirpitz姐姐讲shell的时候是这么讲的(基于senioria的知识, 可能有很多偏差><:
为什么要有shell
一开始的计算机是直接跑程序的, 每个程序都要处理硬盘/内存/IO之类的东西. 在计算机还只是用来做翻译公式这样的活的时候, 这种简单的架构就已经够了; 但是随着程序复杂度的增加, 更多的需求也随之出现: 不同的程序之间需要交互, 需要一个对硬盘的抽象来统合各个程序, 需要有一个组合各个程序, 让它们共同协作的接口…
于是, 操作系统应运而生了, 给程序提供了对硬件和对用户的操作的一层抽象. shell就是操作系统面向用户的, 用于交互的"壳".
shell为什么是这样
让我们跳过计算机蛮荒阶段时的打孔纸带/穿线时期: 那个时候shell也还是不存在的. shell出生的年代, 最流行的交互硬件叫电传打字机(teletypewriter, tty), 它能够把用户键入的内容传输给它连接着的计算机, 也能够把计算机的输出和用户的输入一起打印到相连的纸带上(是打字而非打孔x). 因此一切操作都必须通过类似"说话"/写句子的方式来进行(否则打印出来的内容就会是很麻烦的一团乱麻了)(当然另一个重要的原因是当时计算机的典型用户就是geek).
为什么水了这么多字才进入正题 警告: 下文所介绍的并不是shell历史上的真正发展流程, 只是为了方便理解而生造的一个构造顺序
因为已经有了文件系统的抽象, 一件很自然的事情是通过直接键入程序的可执行文件的文件名来运行这个程序, 然后通过键盘来给它提供输入的数据, 让它把输出的数据直接打印到tty上; 或者让它从特定的文件读取数据, 把输出的数据写到特定的文件中. 这样, 我们现在的shell的语法是这样的: command
, 例如, ls
.
然后, 我们发现, 只有这么简单的输入/输出手段的shell满足不了很多要求, 比如, 很难把数据写到(不是程序的默认文件的)文件中. 让我们来视奸一下我们的shell语法: 为了输入输出排版上的美观, 我们已经规定了一个换行符表示运行这个程序, 这样, 一行内的空间就有了剩余. 因为空格在西文中被普遍用于分词, 同时, 因为空间的限制, 文件名都是由缩写组成的, 也不会有空格, 所以, 我们决定, 命令后用空白字符分开的部分(遵循了c-family的习惯: 空白字符被忽略, 只作为分隔符)是它的参数, 为了通用性, 被作为一整个字符串传递给程序的main函数. 在这里, *NIX shell/dos shell和win32程序产生了分歧: win32程序一般都是直接不带参数启动的(然后用gui来交互), 最多带一个要打开的文件的参数(通过注册为某种类型的文件的关联程序), 所以WinMain函数的命令行是不加分割/处理, 只去掉了可执行文件文件名的一整行, 为了方便程序直接通过这一参数打开文件(设计目标是否真实为此存疑); 而*NIX shell/dos shell的参数是一个重要的和用户交互的手段, 因此会再按照空白把参数分割一遍. 现在, 我们的shell语法是这样的: command (space+ arg)*
, 例如, diff /etc/profile ~/.profile
就会把/etc/profile
和~/.profile
作为两个参数传递给diff
程序.
到了这里, 我们面前有两大问题: 如何指定文件名? 以及, 参数中间有空格怎么办? 后一个问题我们暂且按下不表, 前一个问题似乎有一个很简单的解决方案: 直接用它在文件系统中的完整路径. 但是, 不要说UNIX的创造者那些连create都要缩写成creat的人, 就算对于现代人来说, 指定一个完整路径也是繁杂得不可忍受的. 因此, shell中有了一个"当前目录"的概念, 这样, 我们就有了"相对路径"的概念, 一个文件的位置除了可以用它在文件系统中的绝对位置来指定(“绝对路径”)之外, 还可以用它相对当前目录的位置来指定. 这样, 我们就可以写cat test.txt
, 而不是cat /home/test/test.txt
了.
然后, 我们来思考一下第二个问题: 要传递给程序的参数中间有空格怎么办? 我们不妨想一下C是怎么解决类似的问题的: 字符串总要有一种标记来标记它的结束(标记字符串长度是FORTRAN时代的做法), 那么字符串里需要有这个结束字符怎么办? C的解决方案是, 用一个"转义序列"来表示这个字符. 类似的, shell的解决方案也是用\
(反斜杠后加一个空格)来表示空格这个字符(\\
表示反斜杠), 这样, 我们就可以给程序传递带有空格的参数了.
其实到了这里, 我们已经拥有一个最小的可用的shell了.这个shell的实现留作作业x.
糖
但是, 哪怕是一开始的UNIX shell, 也比这个shell有着多得多的功能. 对于剩下这些功能的介绍… 咕咕咕咕咕咕咕咕!(被打死((((((