鸟哥的 Linux ADSL 私房菜


认识 BASH Shell
最近更新日期:2003/02/10
什么是 Shell
BASH Shell
变量与变量的设定echo, env, set, 变量设定规则, export, unset, 变量的有效范围, read, array, $RANDOM, eval, 重要的环境变量(?, HOME, SHELL, MAIL, HISTSIZE...)
命令别名与历史命令alias(设定命令别名), history, !command,
bash shell 的设定档案source,
万用字符与特殊符号
绝对路径与相对路径
命令重导向 ( redirect )
管线命令 ( pipe )cut, sort, wc, uniq, tee, tr, split,
本章习题练习

什么是 Shell
这应该是个蛮有趣的话题:『什么是 Shell ?』相信只要摸过计算机,对于操作系统(不论是 Linux 、 Unix 或者是 Windows )有点概念的朋友们大多听过这个名词,因为只要有『操作系统』那么就离不开 Shell 这个东西。不过,在讨论 Shell 之前,我们先来了解一下计算机的运作状况吧!举个例子来说:当你要计算机传输出来『音乐』的时候,你的计算机需要什么东西呢
  1. 当然就是需要你的硬件有『声卡芯片』这个硬件配备,否则怎么会有声音;
  2. 操作系统的核心可以支持这个芯片组,当然还需要提供芯片的驱动程序啰;
  3. 需要使用者(就是你)输入发生声音的指令啰!
这就是基本的一个输出声音的需要的步骤!那么也就是说,你必须要『输入』一个指令之后,『硬件』才会透过你下达的指令来工作!嘿嘿!那么硬件如何知道你下达的指令呢?那就是 kernel (核心)的控制工作了!了解了吗?没错!也就是说,我们必须要透过『 Shell 』将我们输入的指令与 Kernel 沟通,好让 Kernel 可以控制硬件来正确无误的工作!基本上,我们可以透过底下这两张图来说明一下:

基本上,替我们工作的是『硬件』,而控制硬件的是『核心』,再来,我们使用者乃是利用『Shell』控制一些 kernel 提供的 『工具 Utility』来操控硬件替我们正确的工作。再进一步来说,由于 kernel 听不懂人类的语言,而人类也没有办法直接记得 kernel 的语言,所以两者的沟通就得藉由 shell 来支援了!(其实早期的 DOS 的文字接口也是使用 shell 来沟通呀!那个 shell 的名称就叫做 command.com ,还记得吗? ^_^)
 
以字面上的意思来说, kernel 是『核心』的意思,而 Shell 是『壳』的意思,呵呵!也就是说, shell 是最外头的咚咚!而 kernel 乃是最内层的的咚咚啦!核心是操作系统的最底层的东西!这个核心里头包括了各种的支持硬件的工具!当然啰,如果你的硬件太新,而你的 kernel 并没有支持的话,那么很抱歉,你的 Shell 能力再怎么强,也没有办法使硬件工作的!这样可以了解了吗?呵呵!没错!使计算机主机工作的正是核心的任务,但是操作核心来替使用者工作的,却是 shell 喔!因此,有时候你的 shell 搞了老半天,硬件却不能工作的时候,请注意,您的『核心』是否正确呢?阿!扯远了!这是 kernel 章节才要说的东西??

BASH Shell
知道什么是 Shell 之后,那么我们来了解一下 Linux 使用的是哪一个 shell 呢?什么!哪一个?难道说 shell 不就是『一个 shell 吗?』哈哈!那可不!由于早年的 Unix 年代,发展者众,所以由于 shell 依据发展者的不同就有许多的版本,例如常听到的 Bourne SHell (sh) 、在 Sun 里头预设的 C SHell、 商业上常用的 K SHell、, 还有 TCSH 等等,每一种 Shell 都各有其特点。至于 Linux 使用的这一种版本就称为『 Bourne Again SHell (简称 bash ) 』,这个 Shell 是 Bourne Shell 的增强版本,也是基准于 GNU 的架构下发展出来的呦!

在介绍 shell 的优点之前,先来说一说 shell 的简单历史吧:第一个流行的 shell 是由 Steven Bourne 发展出来的,为了纪念他所以就称为 Bourne shell ,或直接简称为 sh !而后来另一个广为流传的 shell 是由柏克莱大学的 Bill Joy 设计依附于 BSD 版的 Unix 系统中的 shell ,这个 shell 的语法有点类似 C 语言,所以才得名为 C shell ,简称为 csh !由于在学术界 Sun 主机势力相当的庞大,而 Sun 主要是 BSD 的分支之一,所以 C shell 也是另一个很重要而且流传很广的 shell 之一(因为太多的程序设计师使用的就是 C 语言啦!)!

好了,那么 BASH 是怎么一回事呢?这个 shell 是 GNU 计划中重要的工具软件之一,目前也是 GNU 操作系统中标准的 shell ,他主要兼容于 sh ,并且依据一些使用者需求,而加强的 shell 版本,可以说目前几乎所有的 Linux distribution 都是使用 bash 作为管理核心的主要 shell !因此,不论您使用的是那个 distribution ,你都难逃需要学习 bash 的宿命啦!那么这个 shell 有什么好处,干嘛 Linux 要使用他作为预设的 shell 呢? BASH 主要的优点有底下几个:

在了解了 BASH 的优点之后,再来我们要来讨论的是:那如何在 Shell 提供的环境中下达指令呢?其实很简单的,下达指令的方式为:
[root@test /root]# command [-options] parameter1 parameter2 ...
                     指令     选项      参数(1)    参数(2)

1. command 为指令的名称,例如变换路径的指令为 cd 等等;
2. 中刮号[]并不存在于实际的指令中,而加入参数设定时,通常为 - 号,有时候完整名称会输入 -- 符号;
3. parameter1 parameter2.. 为依附在 option 后面的参数,或者是 command 的参数;
4. command, -options, parameter1.. 这几个咚咚中间以空格来区分,不论空几格 shell 都视为一格;
5. 指令太长的时候,可以使用 \ 符号来跳脱 [Enter] 符号,使指令连续到下一行。

实例:
[root@test /root]# ls -al /root   <==以 ls 列出 /root 这个目录中的隐藏文件与相关的属性参数;
[root@test /root]# ./configure --prefix=/usr/local --with-tcp_wrappers \
> --with-pam     <==这两行实际上是同一行的指令,但是加上 \ 跳脱符号后,指令可以连续到下一行!
[root@test /root]# ls           -al   /root  <==这个指令与第一个相同,空格符不论几个,仅视为一个来处理。

很简单吧!OK!那么再来一个问题:『Shell 是什么时候开始接管 Linux 主机的!?』我们在后面会再提到『开机流程』的介绍,这里先跳过去,假设你的机器已经开机成功了,那么主机便进入等待使用者 login 的状态。当使用者输入了账号与密码,并且顺利的 pass 之后,经过了 shell 的环境变量档案读取功能,最后,使用者进入自己的『家目录』之后,例如 root 的家目录在 /root 底下,一般使用者的家目录则在 /etc/passwd 这个档案里面规定,那么主机就已经丢了一个程序称为 bash 的给你操作啰!

变量与变量的设定:echo, env, set, 变量设定规则, export, unset,
再继续研究 BASH 之前,我们要就变量这个东西来讨论一番,因为在主机里面有太多的数据需要进行存取了,而这些数据都是一些服务所必须的,例如 mail 的存取路径在 /var/spool/mail 、家目录预设在 /home/useraccount 等等,当然我们可以改变这些个变量,但是如果该变量是直接深植于套件当中,那么当你修改了某些参数之后,嘿嘿!你的套件就必须要『由原始码直接更新再编译』才行!这样似乎很麻烦,所以啰,就会有变量这个好东西出来了!
 
举个简单的例子来说, sendmail 的 smtp 存放 mail 路径是经由 /etc/profile 里头的
MAIL="/var/spool/mail/$USER"
来设定的,而当我修改了上面这一个咚咚,然后重新开机之后,嘿嘿嘿嘿!我的邮件就可以存放到不同的路径去了!而且不会有问题!可以顺利的『在 Linux 主机上面』收发。然而问题发生在 pop3 这个服务上面,由于 pop3 的预设路径是在 source code 里头,而且就正是 /var/spool/mail 这个路径,也就是说,不论我怎么修正我的『变量』, pop3 都不为所动!唉~真惨,所以就无法直接以 pop3 来收信了(例如 OutLook 就不能工作了)!会发生密码不接受的问题呢!
此外,例如我们在执行程序的时候,系统怎么知道你的 ls 这个指令放在哪里?原来是有 PATH 这个变量,系统会透过这个变量里面所设定的路径去依序寻找该指令系统,如果找不到的话,那么才在屏幕上显示『 command not found 』字样!这些还都只是系统预设的变量的目的,如果是个人的设定方面:例如你要写一个大型的 script (批次文件)时,有些数据因为可能由于使用者习惯的不同而有差异,比如说路径好了,由于该路径在 script 被使用在相当多的地方,如果下次换了一部主机,都要修改 script 里面的所有路径,那么我一定会疯掉!这个时候如果使用变量,而将该变量的定义写在最前面,后面相关的路径名称都以变量来取代,嘿嘿!那么你只要修改一行就等于修改整篇 script 了!方便的很!所以,良好的程序设计师都会善用变量的定义!(这个部分我们在底下还会再提到!)
 
如果说的学理一点,那么由于在 Linux System 下面,所有的执行续都是需要一个执行码,而就如同上面提到的,你『真正以 shell 来跟 Linux 沟通,是在正确的登入 Linux 之后!』这个时候你就有一个 bash 的执行程序,也才可以真正的经由 bash 来跟系统沟通啰!而在进入 shell 之前,也正如同上面提到的,由于系统需要一些变量来提供他数据的存取(或者是一些环境的设定参数值,例如是否要显示彩色等等的),所以就有一些所谓的『环境变量』需要来读入系统中了!这些环境变量例如 PATH、HOME、MAIL、SHELL等等,都是很重要的,为了区别与自订变量的不同,环境变量通常以大写字符来表示呢!
 
说了那么久,那么到底『什么是变量』呢?简单的说,『变量就是以一组文字或符号等,来取代一些设定或者是一串保留的数据!』,例如:『VBird』就是『鸟哥』,所以当你读取 VBird 的时候,系统自然就会知道!哈!那就是鸟哥!最简单的例子可以取 PATH 来说明!如果你对于『相对路径与绝对路径』还有点印象的话,那么应该晓得『要下达正确的指令,应该需要指定路径与文件名』才行!例如你的 ls 指令应该需要以『/bin/ls』来下达指令才对,那么为何你在任意的路径下都可以执行 ls 呢?而不需要指定路径呢?这是因为系统已经预设了一些『搜寻路径(PATH)』了,所以当你需要执行一些指令的时候,系统就会依照该 PATH 的设定来进行指令的搜寻!而这个 PATH 就是所谓的变量了!那么如何『显示变量』呢?这就需要使用到 echo 这个指令啦!

命令别名与历史命令
bash shell 的设定档案:
万用字符与特殊符号

绝对路径与相对路径
命令重导向
好了,对于『 > , >> 』这两个东西有一定的概念之后,我们来深入的谈一谈『命令输出重导向』的观念吧!如前所述,基本上, Linux 执行的结果中,可以约略的分成『正确输出』与『错误输出』两种方式。例如,当你以一般身份执行 find 这个指令时,例如执行『 find / -name testing 』时,由于你是一般身份,又有些数据夹是不允许一般身份者进入的,所以啰,当你使用 find 时,就会有错误讯息发生了!但同时如果有 testing 这个档案在你可以进入的资料夹当中,那么屏幕也会输出到给你看!因此,就具有正确的与错误的输出两种啰!(分别称为 Stdout 与 Stderror)例如下面为执行结果:里面的『 find: /home/root: Permission denied 』就告诉你该数据夹你没有权限进入,这就是错误的输出了,那么『 /home/test/tseting 』就是正确的输出了!
 
[test @test test]# find / -name testing
find: /home/test1: Permission denied    <==这是错误的输出
find: /home/root: Permission denied       <==这是错误的输出
find: /home/masda: Permission denied      <==这是错误的输出
/home/test/testing                        <==这是『正确』的输出
[test @test test]# 

好了,那么假如我们想要将数据输出到 list 这个档案中呢?执行『 find / -name testing > list 』会有什么结果?呵呵,你会发现 list 里面存了刚刚那个『正确』的输出数据,至于屏幕上还是会有错误的讯息出现呢!伤脑筋!如果想要将正确的与错误的数据分别存入不同的档案中需要怎么做?!呵 呵!其实在数据的重导向方面,正确的写法应该是『 1> 』与『 2> 』才对!但是如果只有 > 则预设是以 1> 来进行数据的!那个 1> 是输出正确数据, 2> 则是错误数据输出项目。也就是说:

好了,那么上面的例子中,我们如何将数据输出到不同的地方去呢?可以这么写:
 
[test @test test]# find / -name testing 1> list_right 2> list_error

这样一来,刚刚执行的结果中,有 Permission 的那几行错误信息都会跑到 list_error 这个档案中,至于正确的输出数据则会存到 list_right 这个档案中啰!这样可以了解了吗?如果有点混乱的话,去休息一下再来看看吧!!


管线命令 ( pipe )
本章习题练习 ( 要看答案请将鼠标移动到『答:』底下的空白处,按下左键圈选空白处即可察看 )
参考文章:
2002/06/27:第一次完成
2003/02/10:重新编排与加入 FAQ

2002/05/20 以来统计人数


Designed by VBird during 2001-2004.  Aerosol Lab.