10.1 认识 BASH 这个 Shell

我们在第一章 Linux 是什么当中提到了: 管理整个计算机硬件的其实是操作系统的核心 (kernel),这个核心是需要被保护的! 所以我们一般使用者就只能通过 shell 来跟核心沟通,以让核心达到我们所想要达到的工作。 那么系统有多少 shell 可用呢?为什么我们要使用 bash 啊?下面分别来谈一谈喔!

10.1.1 硬件、核心与 Shell

这应该是个蛮有趣的话题:“什么是 Shell ”?相信只要摸过计算机,对于操作系统 (不论是 Linux 、 Unix 或者是 Windows) 有点概念的朋友们大多听过这个名词,因为只要有“操作系统”那么就离不开 Shell 这个东西。不过,在讨论 Shell 之前,我们先来了解一下计算机的运行状况吧! 举个例子来说:当你要计算机传输出来“音乐”的时候,你的计算机需要什么东西呢?

  1. 硬件:当然就是需要你的硬件有“声卡芯片”这个配备,否则怎么会有声音;
  2. 核心管理:操作系统的核心可以支持这个芯片组,当然还需要提供芯片的驱动程序啰;
  3. 应用程序:需要使用者 (就是你) 输入发生声音的指令啰!

这就是基本的一个输出声音所需要的步骤!也就是说,你必须要“输入”一个指令之后, “硬件”才会通过你下达的指令来工作!那么硬件如何知道你下达的指令呢?那就是 kernel (核心) 的控制工作了!也就是说,我们必须要通过“ Shell ”将我们输入的指令与 Kernel 沟通,好让 Kernel 可以控制硬件来正确无误的工作! 基本上,我们可以通过下面这张图来说明一下:

硬件、核心与使用者的相关性图示图10.1.1、硬件、核心与使用者的相关性图示

我们在第零章内的操作系统小节曾经提到过, 操作系统其实是一组软件,由于这组软件在控制整个硬件与管理系统的活动监测, 如果这组软件能被使用者随意的操作,若使用者应用不当,将会使得整个系统崩溃!因为操作系统管理的就是整个硬件功能嘛! 所以当然不能够随便被一些没有管理能力的终端用户随意使用啰!

但是我们总是需要让使用者操作系统的,所以就有了在操作系统上面发展的应用程序啦!使用者可以通过应用程序来指挥核心, 让核心达成我们所需要的硬件任务!如果考虑如第零章所提供的操作系统图示(图0.4.2), 我们可以发现应用程序其实是在最外层,就如同鸡蛋的外壳一样,因此这个咚咚也就被称呼为壳程序 (shell) 啰!

其实壳程序的功能只是提供使用者操作系统的一个接口,因此这个壳程序需要可以调用其他软件才好。 我们在第四章到第九章提到过很多指令,包括 man, chmod, chown, vi, fdisk, mkfs 等等指令,这些指令都是独立的应用程序, 但是我们可以通过壳程序 (就是命令行界面) 来操作这些应用程序,让这些应用程序调用核心来运行所需的工作哩! 这样对于壳程序是否有了一定的概念了?

鸟哥的图示

Tips 也就是说,只要能够操作应用程序的接口都能够称为壳程序。狭义的壳程序指的是命令行方面的软件,包括本章要介绍的 bash 等。 广义的壳程序则包括图形接口的软件!因为图形接口其实也能够操作各种应用程序来调用核心工作啊! 不过在本章中,我们主要还是在使用 bash 啦!

10.1.2 为何要学命令行的 shell?

命令行的 shell 是很不好学的,但是学了之后好处多多!所以, 在这里鸟哥要先对您进行一些心理建设,先来了解一下为啥学习 shell 是有好处的,这样你才会有信心继续玩下去 ^_^

  • 命令行的 shell:大家都一样!

鸟哥常常听到这个问题:“我干嘛要学习 shell 呢? 不是已经有很多的工具可以提供我设置我的主机了?我为何要花这么多时间去学指令呢?不是以 X Window 按一按几个按钮就可以搞定了吗?”唉~还是得一再地强调, X Window 还有 Web 接口的设置工具例如 Webmin [1] 是真的好用的家伙, 他真的可以帮助我们很简易的设置好我们的主机,甚至是一些很进阶的设置都可以帮我们搞定。

但是鸟哥在前面的章节里面也已经提到过相当多次了, X Window 与 web 接口的工具,他的接口虽然好友,功能虽然强大, 但毕竟他是将所有利用到的软件都整合在一起的一组应用程序而已, 并非是一个完整的套件,所以某些时候当你升级或者是使用其他套件管理模块 (例如 tarball 而非 rpm 文件等等) 时,就会造成设置的困扰了。甚至不同的 distribution 所设计的 X window 接口也都不相同,这样也造成学习方面的困扰。

命令行的 shell 就不同了!几乎各家 distributions 使用的 bash 都是一样的!如此一来, 你就能够轻轻松松的转换不同的 distributions ,就像武侠小说里面提到的“一法通、万法通!”

  • 远端管理:命令行就是比较快!

此外,Linux 的管理常常需要通过远端连线,而连线时命令行的传输速度一定比较快, 而且,较不容易出现断线或者是信息外流的问题,因此,shell 真的是得学习的一项工具。而且,他可以让您更深入 Linux ,更了解他,而不是只会按一按鼠标而已!所谓“天助自助者!”多摸一点文字模式的东西,会让你与 Linux 更亲近呢!

  • Linux 的任督二脉: shell 是也!

有些朋友也很可爱,常会说:“我学这么多干什么? 又不常用,也用不到!”嘿嘿!有没有听过“书到用时方恨少?” 当你的主机一切安然无恙的时候,您当然会觉得好像学这么多的东西一点帮助也没有呀! 万一,某一天真的不幸给他中标了,您该如何是好?是直接重新安装? 还是先追踪入侵来源后进行漏洞的修补?或者是干脆就关站好了?这当然涉及很多的考虑, 但就以鸟哥的观点来看,多学一点总是好的,尤其我们可以有备而无患嘛!甚至学的不精也没有关系,了解概念也就 OK 啦!毕竟没有人要您一定要背这么多的内容啦!了解概念就很了不起了!

此外,如果你真的有心想要将您的主机管理的好,那么良好的 shell 程序编写是一定需要的啦!就鸟哥自己来说,鸟哥管理的主机虽然还不算多, 只有区区不到十部,但是如果每部主机都要花上几十分钟来查阅他的登录文件信息以及相关的讯息, 那么鸟哥可能会疯掉!基本上,也太没有效率了!这个时候,如果能够借由 shell 提供的数据流重导向以及管线命令,呵呵! 那么鸟哥分析登录信息只要花费不到十分钟就可以看完所有的主机之重要信息了!相当的好用呢!

由于学习 shell 的好处真的是多多啦!所以,如果你是个系统管理员,或者有心想要管理系统的话,那么 shell 与 shell scripts 这个东西真的有必要看一看!因为他就像“打通任督二脉,任何武功都能随你应用”的说!

10.1.3 系统的合法 shell 与 /etc/shells 功能

知道什么是 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 的简单历史吧[2]:第一个流行的 shell 是由 Steven Bourne 发展出来的,为了纪念他所以就称为 Bourne shell ,或直接简称为 sh !而后来另一个广为流传的 shell 是由柏克莱大学的 Bill Joy 设计依附于 BSD 版的 Unix 系统中的 shell ,这个 shell 的语法有点类似 C 语言,所以才得名为 C shell ,简称为 csh !由于在学术界 Sun 主机势力相当的庞大,而 Sun 主要是 BSD 的分支之一,所以 C shell 也是另一个很重要而且流传很广的 shell 之一 。

鸟哥的图示

Tips 由于 Linux 为 C 程序语言撰写的,很多程序设计师使用 C 来开发软件,因此 C shell 相对的就很热门了。 另外,还记得我们在第一章、Linux 是什么提到的吧? Sun 公司的创始人就是 Bill Joy,而 BSD 最早就是 Bill Joy 发展出来的啊。

那么目前我们的 Linux (以 CentOS 7.x 为例) 有多少我们可以使用的 shells 呢? 你可以检查一下 /etc/shells 这个文件,至少就有下面这几个可以用的 shells (鸟哥省略了重复的 shell 了!包括 /bin/sh 等于 /usr/bin/sh 啰!):

  • /bin/sh (已经被 /bin/bash 所取代)
  • /bin/bash (就是 Linux 默认的 shell)
  • /bin/tcsh (整合 C Shell ,提供更多的功能)
  • /bin/csh (已经被 /bin/tcsh 所取代)

虽然各家 shell 的功能都差不多,但是在某些语法的下达方面则有所不同,因此建议你还是得要选择某一种 shell 来熟悉一下较佳。 Linux 默认就是使用 bash ,所以最初你只要学会 bash 就非常了不起了! ^_^! 另外,咦!为什么我们系统上合法的 shell 要写入 /etc/shells 这个文件啊? 这是因为系统某些服务在运行过程中,会去检查使用者能够使用的 shells ,而这些 shell 的查询就是借由 /etc/shells 这个文件啰!

举例来说,某些 FTP 网站会去检查使用者的可用 shell ,而如果你不想要让这些使用者使用 FTP 以外的主机资源时,可能会给予该使用者一些怪怪的 shell,让使用者无法以其他服务登陆主机。 这个时候,你就得将那些怪怪的 shell 写到 /etc/shells 当中了。举例来说,我们的 CentOS 7.x 的 /etc/shells 里头就有个 /sbin/nologin 文件的存在,这个就是我们说的怪怪的 shell 啰~

那么,再想一想,我这个使用者什么时候可以取得 shell 来工作呢?还有, 我这个使用者默认会取得哪一个 shell 啊?还记得我们在第四章的在终端接口登陆linux小节当中提到的登陆动作吧? 当我登陆的时候,系统就会给我一个 shell 让我来工作了。 而这个登陆取得的 shell 就记录在 /etc/passwd 这个文件内!这个文件的内容是啥?

[dmtsai@study ~]$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....(下面省略).....

如上所示,在每一行的最后一个数据,就是你登陆后可以取得的默认的 shell 啦!那你也会看到, root 是 /bin/bash ,不过,系统帐号 bin 与 daemon 等等,就使用那个怪怪的 /sbin/nologin 啰~关于使用者这部分的内容,我们留在第十三章的帐号管理时提供更多的说明。

10.1.4 Bash shell 的功能

既然 /bin/bash 是 Linux 默认的 shell ,那么总是得了解一下这个玩意儿吧!bash 是 GNU 计划中重要的工具软件之一,目前也是 Linux distributions 的标准 shell 。 bash 主要相容于 sh ,并且依据一些使用者需求而加强的 shell 版本。不论你使用的是那个 distribution ,你都难逃需要学习 bash 的宿命啦!那么这个 shell 有什么好处,干嘛 Linux 要使用他作为默认的 shell 呢? bash 主要的优点有下面几个:

  • 命令编修能力 (history):

bash 的功能里头,鸟哥个人认为相当棒的一个就是“他能记忆使用过的指令!” 这功能真的相当的棒!因为我只要在命令行按“上下键”就可以找到前/后一个输入的指令!而在很多 distribution 里头,默认的指令记忆功能可以到达 1000 个!也就是说,你曾经下达过的指令几乎都被记录下来了。

这么多的指令记录在哪里呢?在你的主文件夹内的 .bash_history 啦! 不过,需要留意的是,~/.bash_history 记录的是前一次登陆以前所执行过的指令, 而至于这一次登陆所执行的指令都被暂存在内存中,当你成功的登出系统后,该指令记忆才会记录到 .bash_history 当中!

这有什么优点呢?最大的好处就是可以“查询曾经做过的举动!” 如此可以知道你的执行步骤,那么就可以追踪你曾下达过的指令,以作为除错的重要流程! 但如此一来也有个烦恼,就是如果被骇客入侵了,那么他只要翻你曾经执行过的指令, 刚好你的指令又跟系统有关 (例如直接输入 MySQL 的密码在命令行上面),那你的服务器可就伤脑筋了! 到底记录指令的数目越多还是越少越好?这部份是见仁见智啦,没有一定的答案的。

  • 命令与文件补全功能: ([tab] 按键的好处)

还记得我们在第四章内的重要的几个热键小节当中提到的 [tab] 这个按键吗?这个按键的功能就是在 bash 里头才有的啦!常常在 bash 环境中使用 [tab] 是个很棒的习惯喔!因为至少可以让你 1)少打很多字; 2)确定输入的数据是正确的! 使用 [tab] 按键的时机依据 [tab] 接在指令后或参数后而有所不同。我们再复习一次:

  • [Tab] 接在一串指令的第一个字的后面,则为命令补全;
  • [Tab] 接在一串指令的第二个字以后时,则为“文件补齐”!
  • 若安装 bash-completion 软件,则在某些指令后面使用 [tab] 按键时,可以进行“选项/参数的补齐”功能!

所以说,如果我想要知道我的环境当中所有以 c 为开头的指令呢?就按下“ c[tab][tab] ”就好啦! ^_^! 是的!真的是很方便的功能,所以,有事没事,在 bash shell 下面,多按几次 [tab] 是一个不错的习惯啦!

  • 命令别名设置功能: (alias)

假如我需要知道这个目录下面的所有文件 (包含隐藏文件) 及所有的文件属性,那么我就必须要下达“ ls -al ”这样的指令串,唉!真麻烦,有没有更快的取代方式?呵呵!就使用命令别名呀!例如鸟哥最喜欢直接以 lm 这个自订的命令来取代上面的命令,也就是说, lm 会等于 ls -al 这样的一个功能,嘿!那么要如何作呢?就使用 alias 即可!你可以在命令行输入 alias 就可以知道目前的命令别名有哪些了!也可以直接下达命令来设置别名呦:

  • alias lm='ls -al'

  • 工作控制、前景背景控制: (job control, foreground, background)

这部分我们在第十六章 Linux 程序控制中再提及! 使用前、背景的控制可以让工作进行的更为顺利!至于工作控制(jobs)的用途则更广, 可以让我们随时将工作丢到背景中执行!而不怕不小心使用了 [Ctrl] + c 来停掉该程序!真是好样的!此外,也可以在单一登陆的环境中,达到多任务的目的呢!

  • 程序化脚本: (shell scripts)

在 DOS 年代还记得将一堆指令写在一起的所谓的“批处理文件”吧?在 Linux 下面的 shell scripts 则发挥更为强大的功能,可以将你平时管理系统常需要下达的连续指令写成一个文件, 该文件并且可以通过对谈互动式的方式来进行主机的侦测工作!也可以借由 shell 提供的环境变量及相关指令来进行设计,哇!整个设计下来几乎就是一个小型的程序语言了!该 scripts 的功能真的是超乎鸟哥的想像之外!以前在 DOS 下面需要程序语言才能写的东西,在 Linux 下面使用简单的 shell scripts 就可以帮你达成了!真的厉害!这部分我们在第十二章再来谈!

  • 万用字符: (Wildcard)

除了完整的字串之外, bash 还支持许多的万用字符来帮助使用者查询与指令下达。 举例来说,想要知道 /usr/bin 下面有多少以 X 为开头的文件吗?使用:“ ls -l /usr/bin/X* ”就能够知道啰~此外,还有其他可供利用的万用字符, 这些都能够加快使用者的操作呢!

总之,bash 这么好!不学吗?怎么可能!来学吧! ^_^

10.1.5 查询指令是否为 Bash shell 的内置命令: type

我们在第四章提到关于 Linux 的线上说明文档部分,也就是 man page 的内容,那么 bash 有没有什么说明文档啊?开玩笑~ 这么棒的东西怎么可能没有说明文档!请你在 shell 的环境下,直接输入 man bash 瞧一瞧, 嘿嘿!不是盖的吧!让你看个几天几夜也无法看完的 bash 说明文档,可是很详尽的数据啊! ^_^

不过,在这个 bash 的 man page 当中,不知道你是否有察觉到,咦! 怎么这个说明文档里面有其他的文件说明啊?举例来说,那个 cd 指令的说明就在这个 man page 内? 然后我直接输入 man cd 时,怎么出现的画面中,最上方竟然出现一堆指令的介绍?这是怎么回事? 为了方便 shell 的操作,其实 bash 已经“内置”了很多指令了,例如上面提到的 cd , 还有例如 umask 等等的指令,都是内置在 bash 当中的呢!

那我怎么知道这个指令是来自于外部指令(指的是其他非 bash 所提供的指令) 或是内置在 bash 当中的呢? 嘿嘿!利用 type 这个指令来观察即可!举例来说:

[dmtsai@study ~]$ type [-tpa] name
选项与参数:
    :不加任何选项与参数时,type 会显示出 name 是外部指令还是 bash 内置指令
-t  :当加入 -t 参数时,type 会将 name 以下面这些字眼显示出他的意义:
      file    :表示为外部指令;
      alias   :表示该指令为命令别名所设置的名称;
      builtin :表示该指令为 bash 内置的指令功能;
-p  :如果后面接的 name 为外部指令时,才会显示完整文件名;
-a  :会由 PATH 变量定义的路径中,将所有含 name 的指令都列出来,包含 alias

范例一:查询一下 ls 这个指令是否为 bash 内置?
[dmtsai@study ~]$ type ls
ls is aliased to `ls --color=auto' <==未加任何参数,列出 ls 的最主要使用情况
[dmtsai@study ~]$ type -t ls
alias                              <==仅列出 ls 执行时的依据
[dmtsai@study ~]$ type -a ls
ls is aliased to `ls --color=auto' <==最先使用 aliase
ls is /usr/bin/ls                  <==还有找到外部指令在 /bin/ls

范例二:那么 cd 呢?
[dmtsai@study ~]$ type cd
cd is a shell builtin              <==看到了吗? cd 是 shell 内置指令

通过 type 这个指令我们可以知道每个指令是否为 bash 的内置指令。 此外,由于利用 type 搜寻后面的名称时,如果后面接的名称并不能以可执行文件的状态被找到, 那么该名称是不会被显示出来的。也就是说, type 主要在找出“可执行文件”而不是一般文件文件名喔! 呵呵!所以,这个 type 也可以用来作为类似 which 指令的用途啦!找指令用的!

10.1.6 指令的下达与快速编辑按钮

我们在第四章的开始下达指令小节已经提到过在 shell 环境下的指令下达方法,如果你忘记了请回到第四章再去回忆一下!这里不重复说明了。 鸟哥这里仅就反斜线 (\) 来说明一下指令下达的方式啰!

范例:如果指令串太长的话,如何使用两行来输出?
[dmtsai@study ~]$ cp /var/spool/mail/root /etc/crontab \
> /etc/fstab /root

上面这个指令用途是将三个文件复制到 /root 这个目录下而已。不过,因为指令太长, 于是鸟哥就利用“ [Enter] ”来将 [Enter] 这个按键“跳脱!”开来,让 [Enter] 按键不再具有“开始执行”的功能!好让指令可以继续在下一行输入。 需要特别留意, [Enter] 按键是紧接着反斜线 (\) 的,两者中间没有其他字符。 因为 \ 仅跳脱“紧接着的下一个字符”而已!所以,万一我写成: “ \ [Enter] ”,亦即 [Enter] 与反斜线中间有一个空格时,则 \ 跳脱的是“空白键”而不是 [Enter] 按键!这个地方请再仔细的看一遍!很重要!

如果顺利跳脱 [Enter] 后,下一行最前面就会主动出现 > 的符号, 你可以继续输入指令啰!也就是说,那个 > 是系统自动出现的,你不需要输入。

另外,当你所需要下达的指令特别长,或者是你输入了一串错误的指令时,你想要快速的将这串指令整个删除掉,一般来说,我们都是按下删除键的。 有没有其他的快速组合键可以协助呢?是有的!常见的有下面这些:

组合键 功能与示范
[ctrl]+u/[ctrl]+k 分别是从光标处向前删除指令串 ([ctrl]+u) 及向后删除指令串 ([ctrl]+k)。
[ctrl]+a/[ctrl]+e 分别是让光标移动到整个指令串的最前面 ([ctrl]+a) 或最后面 ([ctrl]+e)。

总之,当我们顺利的在终端机 (tty) 上面登陆后, Linux 就会依据 /etc/passwd 文件的设置给我们一个 shell (默认是 bash),然后我们就可以依据上面的指令下达方式来操作 shell, 之后,我们就可以通过 man 这个线上查询来查询指令的使用方式与参数说明, 很不错吧!那么我们就赶紧更进一步来操作 bash 这个好玩的东西啰!