不知道有没有小伙伴和笔者一样,bash命令看了一遍又一遍,当要写脚本的时候,还是会有些命令模糊,参数记不清。分析原因:一是学习的时候,只是对用到的命令或语法简单的查一下,应付当前的工作,而并没有进行整体梳理和构建完整的知识体系。第二点就是遗忘(笔者有时候记性真是差),遗忘的原因可能就是记忆的不深刻(笔者能够清晰的记着小时候第一次去幼儿园,上到一半翘课拿着好吃的去草地吃完回家的场景- -!)。
从本期开始,笔者将基于linux圣经
《鸟哥的Linux私房菜》中的第十、十一、十二章,和马哥(马永亮)的部分网课内容来重新对自己的bash知识体系进行梳理,力求夯实基础。期间也会引用一些工作中遇到的高手写的脚本作为参考学习。闲言少絮,让我们开始新的旅程!
管理整个计算机硬件的其实是操作系统的核心 (kernel),这个核心是需要被保护的! 所以我们一般使用者就只能透过 shell 来跟核心沟通,以让核心达到我们所想要达到的工作。 那么系统有多少 shell 可用呢?为什么我们要使用 bash 啊?
这应该是个蛮有趣的话题:『什么是 Shell 』?相信只要摸过计算机,对于操作系统 (不论是 Linux 、Unix 或者是 Windows) 有点概念的朋友们大多听过这个名词,因为只要有『操作系统』那么就离不开 Shell 这个东西。不过,在讨论 Shell 之前,我们先来了解一下计算机的运作状况吧! 举个例子来说:当你要计算机传输出来『音乐』的时候,你的计算机需要什么东西呢?
- 硬件:当然就是需要你的硬件有『声卡芯片』这个配备,否则怎么会有声音;
- 核心管理:操作系统的核心可以支持这个芯片组,当然还需要提供芯片的驱动程序啰;
- 应用程序:需要使用者 (就是你) 输入发生声音的指令啰!
这就是基本的一个输出声音所需要的步骤!也就是说,你必须要『输入』一个指令之后, 『硬件』才会透过你下达的指令来工作!那么硬件如何知道你下达的指令呢?那就是 kernel (核心) 的控制工作了!也就是说,我们必须要透过『 Shell 』将我们输入的指令与 Kernel 沟通,好让 Kernel 可以控制硬件来正确无误的工作! 基本上,我们可以透过底下这张图来说明一下:
操作系统其实是一组软件,由于这组软件在控制整个硬件与管理系统的活动监测, 如果这组软件能被用户随意的操作,若使用者应用不当,将会使得整个系统崩溃!因为操作系统管理的就是整个硬件功能嘛! 所以当然不能够随便被一些没有管理能力的终端用户随意使用啰
但是我们总是需要让用户操作系统的,所以就有了在操作系统上面发展的应用程序啦!用户可以透过应用程序来指挥核心, 让核心达成我们所需要的硬件任务!
我们可以发现应用程序其实是在最外层,就如同鸡蛋的外壳一样,因此这个咚咚也就被称呼为壳程序 (shell) 啰!
其实壳程序的功能只是提供用户操作系统的一个接口,因此这个壳程序需要可以呼叫其他软件才好。我们可以透过壳程序 (就是指令列模式) 来操作这些应用程序,让这些应用程序呼叫核心来运作所需的工作哩! 这样对于壳程序是否有了一定的概念了?
也就是说,只要能够操作应用程序的接口都能够称为壳程序。狭义的壳程序指的是指令列方面的软件,包括本章要介绍的 bash 等。 广义的壳程序则包括图形接口的软件!因为图形接口其实也能够操作各种应用程序来呼叫核心工作啊! 不过在本章中,我们主要还是在使用 bash 啦!
文字接口的 shell 是很不好学的,但是学了之后好处多多!
X Window 与 web 接口的工具,他的接口虽然亲善,功能虽然强大, 但毕竟他是将所有利用到的软件都整合在一起的一组应用程序而已, 并非是一个完整的套件,所以某些时候当你升级或者是使用其他套件管理模块 (例如 tarball 而非 rpm 文件等等) 时,就会造成设定的困扰了。甚至不同的 distribution 所设计的 X window 接口也都不相同,这样也造成学习方面的困扰。文字接口的 shell 就不同了!几乎各家 distributions 使用的 bash 都是一样的! 如此一来, 你就能够轻轻松松的转换不同的 distributions ,就像武侠小说里面提到的『一法通、万法通!』
此外,Linux 的管理常常需要透过远程联机,而联机时文字接口的传输速度一定比较快, 而且,较不容易出现断线或者是信息外流的问题,因此,shell 真的是得学习的一项工具。而且,他可以让更深入 Linux ,更了解他,而不是只会按一按鼠标而已!所谓『天助自助者!』多摸一点文本模式的东西,会让你与 Linux 更亲近呢!
知道什么是 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 之一
那么目前我们的 Linux (以 CentOS 7.x 为例) 有多少我们可以使用的 shells 呢? 你可以检查一下/etc/shells 这个文件,至少就有底下这几个可以用的 shells (鸟哥省略了重复的 shell 了!包括 /bin/sh 等于 /usr/bin/sh 啰!):
[root@node-135 ngx_on_cpu]# cat /etc/shells
/bin/sh (已经被 /bin/bash 所取代)
/bin/bash (就是 Linux 预设的 shell)
/bin/tcsh (整合 C Shell ,提供更多的功能)
/bin/csh (已经被 /bin/tcsh 所取代)
/usr/bin/sh
/usr/bin/bash
不同版本的centos,自带的shells可能略有不同
虽然各家 shell 的功能都差不多,但是在某些语法的下达方面则有所不同,因此建议你还是得要选择某一种 shell 来熟悉一下较佳。 Linux 预设就是使用 bash ,所以最初你只要学会 bash 就非常了不起了! _! 另外,咦!为什么我们系统上合法的 shell 要写入 /etc/shells 这个文件啊? 这是因为系统某些服务在运作过程中,会去检查使用者能够使用的 shells ,而这些 shell 的查询就是藉由/etc/shells 这个文件啰!
我这个使用者什么时候可以取得 shell 来工作呢?还有, 我这个使用者预设会取得哪一个 shell 啊?还记得我们在第四章的在终端界面登入 linux 小节当中提到的登入动作吧? 当我登入的时候,系统就会给我一个 shell 让我来工作了。 而这个登入取得的 shell 就记录在/etc/passwd
这个文件内!这个文件的内容是啥?
[root@node-135 ngx_on_cpu]# 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 啰,在后文中会提供更多的说明
BASH 的全称是“Bourne Again Shell”,它是由 FSF 的 Brian Fox 开发。BASH 是 Bourne shell 的后继兼容版本与开放源代码版本。Bourne shell 是 Unix 第七版上使用的 Shell。以简洁、紧凑、高校著称、由 AT&T编写。Bourne Again 的双关语是 born again,新生的意思。黑客的幽默。
既然 /bin/bash 是 Linux 预设的 shell ,那么总是得了解一下这个玩意儿吧!bash 是 GNU 计划中重要的工具软件之一,目前也是 Linux distributions 的标准 shell 。 bash 主要兼容于 sh ,并且依据一些使用者需求而加强的 shell 版本。不论你使用的是那个 distribution ,你都难逃需要学习 bash 的宿命啦!那么这个 shell 有什么好处,干嘛 Linux 要使用他作为预设的 shell 呢? bash 主要的优点有底下几个:
通配符简介:除了完整的字符串之外, bash 还支持许多的通配符来帮助用户查询与指令下达。 举例来说,想要知道 /usr/bin 底下有多少以 X 为开头的文件吗?使用:『 ls -l /usr/bin/X* 』就能够知道啰~此外,还有其他可供利用的通配符, 这些都能够加快使用者的操作呢!
到关于 Linux 的联机帮助文件部分,也就是 man page 的内容,那么 bash 有没有什么说明文件啊?开玩笑~ 这么棒的东西怎么可能没有说明文件!请你在 shell 的环境下,直接输入man bash
瞧一瞧, 嘿嘿!不是盖的吧!让你看个几天几夜也无法看完的 bash 说明文件,可是很详尽的数据啊! _
不过,在这个 bash 的 man page 当中,不知道你是否有察觉到,咦! 怎么这个说明文件里面有其他的文件说明啊?举例来说,那个 cd 指令的说明就在这个 man page 内? 然后我直接输入 man cd 时,怎么出现的画面中,最上方竟然出现一堆指令的介绍?这是怎么回事? 为了方便 shell 的操作,其实 bash 已经『内建』了很多指令了,例如上面提到的 cd , 还有例如 umask 等等的指令,都是内建在 bash 当中的呢!
那我怎么知道这个指令是来自于外部指令(指的是其他非 bash 所提供的指令) 或是内建在 bash 当中的呢? 嘿嘿!利用 type
这个指令来观察即可!举例来说:
type [-tpa] name
选项与参数:
:不加任何选项与参数时,type 会显示出 name 是外部指令还是 bash 内建指令
-t :当加入 -t 参数时,type 会将 name 以底下这些字眼显示出他的意义:
file :表示为外部指令;
alias :表示该指令为命令别名所设定的名称;
builtin :表示该指令为 bash 内建的指令功能;
-p :如果后面接的 name 为外部指令时,才会显示完整文件名;
-a :会由 PATH 变量定义的路径中,将所有含 name 的指令都列出来,包含 alias
[root@node-135 /]# type -a java
java is /usr/bin/java
java is /opt/jdk-11.0.19/bin/java
[root@node-135 /]# type -t java
file
[root@node-135 /]# type -t cd
builtin
[root@node-135 /]# type -p java
/usr/bin/java
[root@node-135 /]# type java
java is /usr/bin/java
[root@node-135 /]# type ls
ls is aliased to `ls --color=auto'
[root@node-135 /]# type cd
cd is a shell builtin
透过 type 这个指令我们可以知道每个指令是否为 bash 的内建指令。 此外,由于利用 type 搜寻后面的名称时,如果后面接的名称并不能以执行档的状态被找到, 那么该名称是不会被显示出来的。也就是说, type 主要在找出『执行档』而不是一般文件档名喔! 呵呵!所以,这个 type 也可以用来作为类似 which 指令的用途啦!找指令用的!
如果指令串太长的话,如何使用两行来输出?
[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) |