1700436560
1700436561
1700436563
UNIX传奇:历史与回忆 5.1 伯恩的shell
1700436564
1700436565
利用第6版shell中的I/O重定向和管道,很容易就能将程序组合起来做一些任务,最初的做法是输入一连串命令,将它们汇集在一个文件(shell脚本)中,这样就可以作为单条命令来执行了。
1700436566
1700436567
第6版shell提供了用于按条件执行命令的if语句,用于跳转到脚本文件另一行的goto语句,还有在脚本中标记出某一行的方法(“
:”命令,什么都不做),带这个标记的行可以作为跳转执行目标。有了这些命令,就能实现循环操作,所以原则上第6版shell可以用来写复杂的脚本。然而,在实践中,这些机制既笨拙又脆弱。
1700436568
1700436569
正如我在下一章中会提到的那样,程序员工作台(Programmer’s Workbench,PWB[2])小组的成员约翰·马希往第6版shell中增加了一些自定义功能,使其更适合编程。这些功能包括:用于测试条件的if-then-else语句,用于循环的while语句,以及用于在shell文件中存储信息的变量。
1700436570
1700436571
1976年,刚刚加入1127中心的史蒂夫·伯恩(Steve Bourne)编写了一个新shell。它融合PWB shell的功能,同时还有其他重大改进。他的目标是保留现有shell易于交互的优点,同时也使其成为一种完全可编程的脚本语言。史蒂夫的shell提供了控制流结构,包括if-then-else、while、for和case。它还支持变量,其中一些变量由shell定义,另一些变量则可以由用户定义。引用机制[3]也得到了加强。最后,我们把它改得像其他程序一样能够成为管道执行流程中的过滤器。结果,伯恩的shell程序(被简称为sh)很快取代了第6版shell。
1700436572
1700436573
新shell的控制流语法基于史蒂夫喜欢的ALGOL 68语言,但1127中心并没有很多人喜欢ALGOL 68。例如,ALGOL 68使用单词的字符反转形式作为终止符,如fi终止if,esac终止case。但由于od已被占用(八进制转储命令),所以do的终止符是done。
1700436574
1700436575
for i in $* loop over all argumentsdo if grep something $i then echo found something in $i else echo something not found in $i fidone
1700436576
1700436577
1700436578
1700436579
1700436580
1700436581
if和while语句用程序返回的状态作为判断条件,也就是程序可以借返回数值来汇报执行情况,如程序是否正常工作。这种处理方式当时还很罕见,所以大多数程序的返回值都轻率随意。史蒂夫安排shell在每次程序没有返回合理状态时输出一条恼人的消息。程序自动“话痨”持续一周之后,大多数程序都升级了,开始返回有意义的状态值。
1700436582
1700436583
史蒂夫的shell还大大丰富了I/O重定向功能。第6版shell手册的“缺陷”一节上说“无法重定向诊断性输出”。史蒂夫的shell将标准错误流(默认情况下是文件描述符2)和标准输出(文件描述符1)分开,这样脚本的输出就可以直接指向一个文件,而错误信息则去了别的地方,通常是终端。这个新特性特别有用。
1700436584
1700436585
prog >file # stdout to file, stderr to terminalprog 2>err # stdout to terminal, stderr to errprog 1>file 2>err # stdout to file, stderr to errprog >file 2>&1 # merge stderr with stdout
1700436586
1700436587
1700436588
1700436589
1700436590
1700436591
至此,shell已经成为真正的编程语言,适用于编写几乎所有可以合理地梳理为命令序列的东西。它经常能很好地完成这个任务,以至于不再需要编写C语言程序。
1700436592
1700436593
在之后的多年里,更多的功能被添加进来,Bash(Bourne Again Shell的简写,意为“伯恩再来shell”)已经成为大多数Linux和macOS用户事实上的标准shell。虽然个人用的shell脚本往往小而简单,但编译器之类主要工具的源代码分发时往往附带2万行或更多的配置脚本。这些脚本运行程序来测试环境属性,例如,库是否存在和数据类型的大小,因此它们可以编译出经过调整的版本,去适应特定的系统。
1700436594
1700436595
1700436596
1700436597
1700436599
UNIX传奇:历史与回忆 5.2 Yacc,Lex,Make
1700436600
1700436601
我们使用语言进行交流,更好的语言可以帮助我们更有效地进行交流。对于用来与计算机交流的人工语言来说,尤其如此。我们希望只说一句“干吧”,计算机就能照办。但为了完成某些工作,我们却只能不厌其烦地说明细节。优秀的编程语言能降低人类与计算机沟通的成本。计算机领域的大量研究都关乎如何创造富有表达能力的语言。
1700436602
1700436603
第7版Unix提供了多种基于语言的工具,其中一些相当新颖。可以说,如果没有Yacc等工具让非专家也能很容易地创造新语言,这些语言中的大多数都不会存在。本节将介绍语言构建工具。总的来说,Unix工具促进了新语言的创造,从而带来了与计算机交流的更好方式。读者可以放心地跳过细节描述,但领会工具促进语言的概念很重要。
1700436604
1700436605
计算机语言的特点主要有两个方面,语法和语义。语法规定了语言是怎样的,什么符合语法,什么不符合语法。语法还定义了语句和函数如何写,算术和逻辑运算符是什么,它们如何组合成表达式,什么名称是合规的,哪些词是保留字,文本字符串和数字如何表达,程序如何格式化等规则。
1700436606
1700436607
语义是指合规语法被赋予的意义:合乎语法的构造的含义或作用是什么。对于第2章中的面积计算程序:
1700436608
1700436609
void main() { float length, width, area; scanf(“%f %f”, &length, &width); area = length * width; printf(“area = %f\n”, area); }
[
上一页 ]
[ :1.70043656e+09 ]
[
下一页 ]