Linux Shell进化简史

blogdaren 2014-10-13 抢沙发 974人次

导读:M.Tim Jones 是 developerWorks 全球网站的一位多产撰稿人,他的文章涉及的主题非常广泛而有深度。Tim 为了让大家全面了解 Linux,推出了一系列内核剖析方面的文章,深受大家的欣赏;随着 Linux 在虚拟化技术方面的日臻成熟,Tim 及时为我们带来了相关内容的介绍。在本文中,他为我们带来了Linux Shell的进化史。以下为全文

计算机上的大多数日常工作任务,通过鼠标点击即可完成,但要想真正发挥Linux本身的威力,还需要Shell和命令行。Shell就如同编辑器一样,你可以根据个人爱好选择。虽然不同的Shell可以提供不同的功能,但是它们的核心开发思想都是一致的。

现在让我们来追寻Shell的发展足迹,并探讨几个现在流行的Shell。

Shell的历史

Shell也称命令行解释器,有着悠久的历史,我们从第一个UNIX Shell说起。

V6 Shell

1971年,贝尔实验室的Ken Thompson为UNIX开发了第一个Shell——V6 Shell。类似于它在Multics上的前身,V6 Shell(/bin/sh)是一个在内核之外执行的独立的用户程序。

诸如通配符(模式匹配参数扩展,如*.txt)之类的概念在独立的glob实用程序中实现,如同if命令评估条件表达式一样。这种实现保证了Shell的短小精悍,它只有不到900行的C源代码。

V6 Shell引入了一系列简洁的语法,用于重定向(< >和>>)和管道(|或^),并一直沿用至今。你也会发现,它提供了对顺序调用命令(;)和异步命令(&)的支持。

Thompson Shell(即V6 Shell)的缺陷在于脚本编程能力的不足,它只是一个交互性的命令解释器。

Bourne Shell

1977年,Stephen Bourne在贝尔实验室为V7 UNIX开发了Bourne Shell,并一直沿用至今。很多情况下,它甚至是默认的Shell。Bourne Shell是用C语言开发的,但相比其他Shell,其语法更类似于算法语言(ALGOL)。

Bourne Shell的设计有两个目标:作为命令行解释器交互执行操作系统命令和脚本编程。

为了取代Thompson Shell,Bourne Shell有着巨大的优势:

1.在脚本中引入了控制流、循环和变量,提供了更强大的语言与操作系统交互

2.允许使用脚本作为筛选器,为处理信号提供集成支持,但缺乏自定义函数机制

3.纳入了一系列今天我们仍在使用的功能,包括命令替换、here-document等

Bourne Shell在前进的道路上迈出了至关重要的一步,同时也成了其他派生Shell的基石。Bourne Shell的出现推动了Korn shell (ksh)、Almquist Shell(ash)和流行的Bourne Again Shell(Bash)的开发,在Bourne Shell发布之际,C Shell也已在开发之中。下图显示了Shell之间的血缘关系。

33.gif

图一:Shell之间的传承

Shell的基础架构

Linux Shell的基础架构并不复杂,如下图所示。

44.gif

图二:Linux Shell基础架构示意图

Linux Shell的架构看起来非常类似于一条管道,对输入进行语法解析、符号扩展,最后执行。

探索Linux Shell

接下来,让我们来探讨几个Shell,看看它们为Linux Shell的发展做出了哪些贡献。

C Shell

1978年,Bill Joy还在加州大学伯克利分校读书的时候,就为BSD UNIX(Berkeley Software Distribution UNIX)开发了C Shell。

五年之后,C Shell引入了Tenex系统中的一些功能,如命令行编辑功能和文件名和命令自动补全功能。Tenex C shell(tcsh)保持了对csh的向后兼容,并且提升了整体的交互性,它是Ken Greer在卡内基-梅隆大学开发出来的。

C Shell的一个主要设计目标就是创建一种语法类似于C语言的脚本语言,因为C语言在当时非常流行,而且UNIX是用C来开发的。

Bill Joy在C Shell中引入的另一个重要特性是命令历史记录。此功能可以保留之前执行的命令的历史记录,并允许用户查看并选择执行之前的命令。

例如,键入history命令可以查看之前执行的命令,使用上下箭头键可以选择一个命令,使用!!可以执行前一个命令。引用前一个命令的参数也是可以的,比如,!*可以引用前一个命令的所有参数,!$可以引用前一个命令的最后一个参数。

请参看下面的一个Tcsh脚本示例,这个脚本使用了一个参数(目录名称),统计该目录下所有可执行文件的数目。

代码1:在tcsh中统计可执行文件的数目

    #!/bin/tcsh 
    # find all executables 
     
    set count=0 
     
    # Test arguments 
    if ($#argv != 1) then 
    echo "Usage is $0 <dir>" 
      exit 1 
    endif 
     
    # Ensure argument is a directory 
    if (! -d  $1) then 
      echo "$1 is not a directory." 
      exit 1 
    endif 
     
    # Iterate the directory, emit executable files 
    foreach filename ($1/*) 
      if (-x $filename) then 
        echo $filename 
        @ count = $count + 1 
      endif 
    end 
     
    echo 
    echo "$count executable files found." 
     
    exit 0  

Korn Shell

Korn Shell是由David Korn设计的,差不多跟Tenex C Shell同时发布。除了向后兼容Bourne Shell,Korn Shell最引人瞩目的特性就是支持脚本编程。

Korn Shell原来是专有软件,直到2000年,它才(遵照通用公共许可协议)作为开源软件发布。除了对Bourne提供很好的兼容性,Korn Shell还包含了一些来自其他Shell的功能,如csh的历史记录功能。它还提供了一些更先进的功能,这些功能可以在诸如Ruby和Python之类 的现代脚本语言中找到——例如,关联数组和浮点运算。

Korn Shell在许多操作系统上都是可用的,这些系统包括IBM AIX and HP-UX。Korn Shell努力支持Portable Operating System Interface for UNIX(POSIX)Shell语言的标准。

我们来看一下在Korn Shell中统计可执行文件数目脚本的例子:

代码2:在Korn Shell中统计可执行文件的数目

    #!/usr/bin/ksh 
    # find all executables 
     
    count=0 
     
    # Test arguments 
    if [ $# -ne 1 ] ; then 
      echo "Usage is $0 <dir>" 
      exit 1 
    fi 
     
    # Ensure argument is a directory 
    if [ ! -d  "$1" ] ; then 
      echo "$1 is not a directory." 
      exit 1 
    fi 
     
    # Iterate the directory, emit executable files 
    for filename in "$1"/* 
    do 
      if [ -x "$filename" ] ; then 
        echo $filename 
        count=$((count+1)) 
      fi 
    done 
     
    echo 
    echo "$count executable files found." 
     
    exit 0  
Bourne-Again Shell

Bourne-Again Shell,即bash,是一个开源的GNU项目,旨在替换Bourne Shell。Bourne-Again Shell由Brian Fox开发,现在已经成为最流行的Shell之一,被广泛应用在Linux、Darwin、Windows和Cygwin之上。

除了支持脚本的向后兼容性,bash还吸收了Korn Shell和C Shell的一些特性。例如,命令历史记录,命令行编辑,目录堆栈,很多实用的环境变量,命令行自动完成,等等。

Bash继续发展了一些新的特性,如支持正则表达式和关联数组。

虽然一些特性是bash独有的,但我们仍然可以编写与其他脚本语言相兼容的脚本。下面是在bash中统计可执行文件数目的脚本示例。

代码3:在Bourne-Again Shell中统计可执行文件的数目

    #!/bin/bash 
    # find all executables 
     
    count=0 
     
    # Test arguments 
    if [ $# -ne 1 ] ; then 
      echo "Usage is $0 <dir>" 
      exit 1 
    fi 
     
    # Ensure argument is a directory 
    if [ ! -d  "$1" ] ; then 
      echo "$1 is not a directory." 
      exit 1 
    fi 
     
    # Iterate the directory, emit executable files 
    for filename in "$1"/* 
    do 
      if [ -x "$filename" ] ; then 
        echo $filename 
        count=$((count+1)) 
      fi 
    done 
     
    echo 
    echo "$count executable files found." 
     
    exit 0  
这些Shell之间的一个关键区别是它们使用了不同的授权。Bash是一个GNU项目,遵循GPL授权,而C Shell则遵循了BSD许可,Korn Shell则遵循了通用公共许可证。

早期Shell的许多理念和接口在35年之后依然保持不变,这对其作者是一个巨大的肯定。任何一个行业都在不断重塑自我,Shell也在发生着历史的变迁。尽管许多新的Shell被开发出来,但Bourne Shell及其后继者依然是现在的首选。

版权声明:除非注明,本文由( blogdaren )原创,转载请保留文章出处。

本文链接:Linux Shell进化简史

发表评论:

您的昵称:
电子邮件:
个人主页: