第11章、 认识与学习 BASH

11.1. 认识 BASH 这个 Shell
管理整个计算机硬件的其实是操作系统的核心 (kernel),这个核心是需要被保护的! 所以我们一般使用者就只能透过 shell 来跟核心沟通,以让核心达到我们所想要达到的工作。

11.1.1. 硬件、核心与 Shell
只要有『操作系统』那么就离不开 Shell 这个东西。不过,在讨论 Shell 之前,我们先来了解一下计算机的运作状况!
1. 硬件;
2. 核心管理;
3. 应用程序!

这就是基本的一个输出声音所需要的步骤!也就是说,你必须要『输入』一个指令之后, 『硬件』才会透过你下达的指令来工作!那么硬件如何知道你下达的指令呢?那就是 kernel (核心) 的控制工作了!也就是说,我们必须要透过『 Shell 』将我们输入的指令与 Kernel 沟通,好让 Kernel 可以控制硬件来正确无误的工作 ! 基本上,我们可以透过底下这张图来说明一下:
这里写图片描述
操作系统其实是一组软件,由于这组软件在控制整个硬件与管理系统的活动监测, 如果这组软件能被用户随意的操作,若使用者应用不当,将会使得整个系统崩溃 !因为操作系统管理的就是整个硬件功能! 所以当然不能够随便被一些没有管理能力的终端用户随意使用!
但是我们总是需要让用户操作系统的,所以就有了在操作系统上面发展的应用程序!用户可以透过应用程序来指挥核心, 让核心达成我们所需要的硬件任务! 我们可以发现应用程序其实是在最外局,因此被称呼为壳程序 (shell) !
其实壳程序的功能只是提供用户操作系统的一个接口,因此这个壳程序需要可以呼叫其他软件才好。 我们在第五章到第十章提到过很多指令,包括 man, chmod, chown, vi, fdisk, mkfs 等等指令,这些指令都是独立的应用程序, 但是我们可以透过壳程序 (就是指令列模式) 来操作这些应用程序,让这些应用程序呼叫核心来运作所需的工作!

11.1.2. 为何要学文字接口的 shell
文字接口的 shell 是很不好学的,但是学了之后好处多多 !

一、文字接口的 shell:大家都一样!
X Window 还有 Web 接口的设定工具例如 Webmin (注1) 是真的好用的家伙, 他真的可以帮助我们很简易的设定好我们的主机,甚至是一些很进阶的设定都可以帮我们搞定。
X Window 与 web 接口的工具,他的接口虽然亲善,功能虽然强大, 但毕竟他是将所有利用到的软件都整合在一起的一组应用程序而已, 并非是一个完整的套件,所以某些时候当你升级或者是使用其他套件管理模块 (例如 tarball 而非 rpm 档案等等) 时,就会造成设定的困扰了。甚至不同的 distribution 所设计的 X window 接口也都不相同,这样也造成学习方面的困扰。
文字接口的 shell 就不同了!几乎各家 distributions 使用的 bash 都是一样的!

二、进程管理:文字接口就是比较快!
此外,Linux 的管理常常需要透过远程联机,而联机时文字接口的传输速度一定比较快, 而且,较不容易出现断线或者是信息外流的问题,因此,shell 真的是得学习的一项工具。而且,他可以让您更深入 Linux ,更了解他,而不是只会按一按鼠标而已!

三、Linux 的任督二脉: shell 是也!
多学一点总是好的,尤其我们可以有备而无患!甚至学的不精也没有关系!
此外,如果你真的有心想要将您的主机管理的好,那么良好的 shell 程序编写是一定需要的 !这个时候,如果能够藉由 shell 提供的数据流重导向以及管线命令,分析登录信息只要花费不到十分钟就可以看完所有的主机之重要信息了!学习 shell 的好处真的是多多!

11.1.3. 系统的合法 shell 与 /etc/shells 功能
Linux 使用的这一种版本就称为『 Bourne Again SHell (简称 bash) 』,这个 Shell 是 Bourne Shell 的增强版本,也是基准于 GNU 的架构下发展出来的!
那么目前我们的 Linux (以 CentOS 5.x 为例) 有多少我们可以使用的 shells 呢? 你可以检查一下 /etc/shells 这个档案,至少就有底下这几个可以用的 shells:
- /bin/sh (已经被 /bin/bash 所取代)
- /bin/bash (就是 Linux 预设的 shell)
- /bin/ksh (Kornshell 由 AT&T Bell lab. 发展出来的,兼容于 bash)
- /bin/tcsh (整合 C Shell ,提供更多的功能)
- /bin/csh (已经被 /bin/tcsh 所取代)
- /bin/zsh (基于 ksh 发展出来的,功能更强大的 shell)

Linux 预设就是使用 bash ,咦!为什么我们系统上合法的 shell 要写入 /etc/shells 这个档案啊? 这是因为系统某些服务在运作过程中,会去检查使用者能够使用的 shells ,而这些 shell 的查询就是藉由 /etc/shells 这个档案!
举例来说,某些 FTP 网站会去检查使用者的可用 shell ,而如果你不想要让这些用户使用 FTP 以外的主机资源时,可能会给予该使用者一些怪怪的 shell,让使用者无法以其他服务登入主机。 这个时候,你就得将那些怪怪的 shell 写到 /etc/shells 当中了。举例来说,我们的 CentOS 5.x 的 /etc/shells 里头就有个 /sbin/nologin 档案的存在,这个就是我们说的怪怪的 shell 。
那么,再想一想,我这个使用者什么时候可以取得 shell 来工作呢?还有, 我这个使用者预设会取得哪一个 shell 啊?还记得我们在第五章的在终端界面登入linux小节当中提到的登入动作吧? 当我登入的时候,系统就会给我一个 shell 让我来工作了。 而这个登入取得的 shell 就记录在 /etc/passwd 这个档案内!这个档案的内容是啥?
这里写图片描述
如上所示,在每一行的最后一个数据,就是你登入后可以取得的预设的 shell !那你也会看到, root 是 /bin/bash ,不过,系统账号 bin 与 daemon 等等,就使用那个怪怪的 /sbin/nologin 。关于使用者这部分的内容,我们留在第十四章的账号管理时提供更多的说明。

11.1.4. Bash shell 的功能
bash 是 GNU 计划中重要的工具软件之一,目前也是 Linux distributions 的标准 shell 。 bash 主要兼容于 sh ,并且依据一些使用者需求,而加强的 shell 版本。不论你使用的是那个 distribution ,你都难逃需要学习 bash 的! bash 主要的优点有底下几个:

一、命令编修能力 (history):
bash 的功能里头相当棒的一个就是『他能记忆使用过的指令!』 因为我只要在指令列按『上下键』就可以找到前/后一个输入的指令!而在很多 distribution 里头,默认的指令记忆功能可以到达 1000 个!也就是说, 你曾经下达过的指令几乎都被记录下来了。
这么多的指令记录在你的家目录内的 .bash_history 啦! 不过,需要留意的是,~/.bash_history 记录的是前一次登入以前所执行过的指令, 而至于这一次登入所执行的指令都被暂存在内存中,当你成功的注销系统后,该指令记忆才会记录到 .bash_history 当中 !
最大的好处就是可以『查询曾经做过的举动 !』 如此可以知道你的执行步骤,那么就可以追踪你曾下达过的指令,以作为除错的工具! 但如此一来也有个烦恼,就是如果被黑客入侵了,那么他只要翻你曾经执行过的指令, 刚好你的指令又跟系统有关 (例如直接输入 MySQL 的密码在指令列上面),那你的主机可就伤脑筋了!

二、命令与档案补全功能: ([tab] 按键的好处)
还记得我们在第五章内的重要的几个热键小节当中提到的 [tab] 这个按键吗?这个按键的功能就是在 bash 里头才有的!常常在 bash 环境中使用 [tab] 是个很棒的习惯!因为至少可以让你 1)少打很多字; 2)确定输入的数据是正确的! 使用 [tab] 按键的时机依据 [tab] 接在指令后或参数后而有所不同。我们再复习一次:
- [Tab] 接在一串指令的第一个字的后面,则为命令补全;
- [Tab] 接在一串指令的第二个字以后时,则为『档案补齐』!

所以说,如果我想要知道我的环境中,所有可以执行的指令有几个? 就直接在 bash 的提示字符后面连续按两次 [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* 』就能够知道!

11.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 这个指令来观察即可!举例来说:
这里写图片描述
这里写图片描述
透过 type 这个指令我们可以知道每个指令是否为 bash 的内建指令。 此外,由于利用 type 搜寻后面的名称时,如果后面接的名称并不能以执行档的状态被找到, 那么该名称是不会被显示出来的。也就是说, type 主要在找出『执行档』而不是一般档案档名! 所以,这个 type 也可以用来作为类似 which 指令的用途!找指令用的!

11.1.6. 指令的下达
这里仅就反斜杠 () 来说明一下指令下达的方式!
这里写图片描述
上面这个指令用途是将三个档案复制到 /root 这个目录下而已。不过,因为指令太长, 即 [Enter] 与反斜杠中间有一个空格时,则 \ 跳脱的是『空格键』而不是 [Enter] 按键!这个地方请再仔细的看一遍!
如果顺利跳脱 [Enter] 后,下一行最前面就会主动出现 > 的符号。
总之,当我们顺利的在终端机 (tty) 上面登入后, Linux 就会依据 /etc/passwd 档案的设定给我们一个 shell (预设是 bash),然后我们就可以依据上面的指令下达方式来操作 shell, 之后,我们就可以透过 man 这个在线查询来查询指令的使用方式与参数说明!

11.2. Shell 的变量功能
变量是 bash 环境中非常重要的一个玩意儿,我们知道 Linux 是多人多任务的环境,每个人登入系统都能取得一个 bash , 每个人都能够使用 bash 下达 mail 这个指令来收受『自己』的邮件,问题是, bash 是如何得知你的邮件信箱是哪个档案? 这就需要『变量』的帮助!

11.2.1. 什么是变量?
我们可以『用一个简单的 “字眼” 来取代另一个比较复杂或者是容易发动的数据』。最大的好处就是『方便!』。

一、变数的可变性与方便性
我们使用信件读取指令 mail 来读取自己的邮件信箱时,这支程序可以直接读取 MAIL 这个变量的内容, 就能够自动的分辨出属于自己的信箱信件!这样一来,设计程序的设计师就真的很方便的!
这里写图片描述
如上图所示,由于系统已经帮我们规划好 MAIL 这个变量,所以用户只要知道 mail 这个指令如何使用即可, mail 会主动的取用 MAIL 这个变量,就能够如上图所示的取得自己的邮件信箱了!(注意大小写,小写的 mail 是指令, 大写的 MAIL 则是变量名称!)
那么使用变量真的比较好吗?这是当然的!想象一个例子,如果 mail 这个指令将 root 收信的邮件信箱 (mailbox) 档名为 /var/spool/mail/root 直接写入程序代码中。那么当 dmtsai 要使用 mail 时,将会取得 /var/spool/mail/root 这个档案的内容! 不合理吧!所以你就需要帮 dmtsai 也设计一个 mail 的程序,将 /var/spool/mail/dmtsai 写死到 mail 的程序代码当中! 天吶!那系统要有多少个 mail 指令啊?反过来说,使用变量就变的很简单了!因为你不需要更动到程序代码! 只要将 MAIL 这个变量带入不同的内容即可让所有使用者透过 mail 取得自己的信件!简单多了!

二、影响 bash 环境操作的变量
某些特定变量会影响到bash 的环境!举例来说,我们前面已经提到过很多次的那个 PATH 变数! 你能不能在任何目录下执行某个指令,与 PATH 这个变量有很大的关系。例如你下达 ls 这个指令时,系统就是透过 PATH 这个变量里面的内容所记录的路径顺序来搜寻指令的!如果在搜寻完 PATH 变量内的路径还找不到 ls 这个指令时, 就会在屏幕上显示『 command not found 』的错误讯息了。
如果说的学理一点,那么由于在 Linux System 下面,所有的执行续都是需要一个执行码, 而就如同上面提到的,你『真正以 shell 来跟 Linux 沟通,是在正确的登入 Linux 之后!』这个时候你就有一个 bash 的执行程序,也才可以真正的经由 bash 来跟系统沟通!而在进入 shell 之前,也正如同上面提到的,由于系统需要一些变量来提供他数据的存取 (或者是一些环境的设定参数值, 例如是否要显示彩
色等等的) ,所以就有一些所谓的『环境变量』 需要来读入系统中了!这些环境变量例如 PATH、HOME、MAIL、SHELL 等等,都是很重要的, 为了区别与自定义变量的不同,环境变量通常以大写字符来表示!

三、脚本程序设计 (shell script) 的好帮手
这些还都只是系统默认的变量的目的,如果是个人的设定方面的应用呢:例如你要写一个大型的 script 时,有些数据因为可能由于用户习惯的不同而有差异,比如说路径好了,由于该路径在 script 被使用在相当多的地方,如果下次换了一部主机,都要修改 script 里面的所有路径,那么我一定会疯掉! 这个时候如果使用变量,而将该变量的定义写在最前面,后面相关的路径名称都以变量来取代, 那么你只要修改一行就等于修改整篇 script 了!方便的很!所以,良好的程序设计师都会善用变量的定义!
这里写图片描述
最后我们就简单的对『什么是变量』作个简单定义好了: 『变量就是以一组文字或符号等,来取代一些设定或者是一串保留的数据!』, 例如:我设定了『myname』就是『VBird』,所以当你读取 myname 这个变量的时候,系统自然就会知道!那就是 VBird ! 那么如何『显示变量』?这就需要使用到 echo 这个指令!

11.2.2. 变量的取用与设定:echo, 变量设定规则, unset
你可以利用 echo 这个指令来取用变量, 但是,变量在被取用时,前面必须要加上钱字号『 $ 』才行,举例来说,要知道 PATH 的内容,该如何是好?

一、变量的取用: echo
这里写图片描述
变量的取用就如同上面的范例,利用 ehco 就能够读出,只是需要在变量名称前面加上 $ , 或者是以 ${变量} 的方式来取用都可以!当然那个 echo 的功能可是很多的。
这里写图片描述
现在我们知道了变量与变量内容之间的相关性了,用『等号(=)』连接变量与他的内容就好!举例来说: 我要将 myname 这个变量名称的内容设定为 VBird ,那么:
这里写图片描述
在 bash 当中,当一个变量名称尚未被设定时,预设的内容是『空』的。 另外,变量在设定时,还是需要符合某些规定的,否则会设定失败! 这些规则如下所示!

二、变量的设定规则
1.变量与变量内容以一个等号『=』来连结,如下所示: 『myname=VBird』 ;
2.等号两边不能直接接空格符,如下所示为错误: 『myname = VBird』或『myname=VBird Tsai』 ;
3.变量名称只能是英文字母与数字,但是开头字符不能是数字,如下为错误: 『2myname=VBird』 ;
4.变量内容若有空格符可使用双引号『”』或单引号『’』将变量内容结合起来,但
- 双引号内的特殊字符如 $ 等,可以保有原本的特性,如下所示: 『var=”lang is $LANG”』则『echo $var』可得『lang is en_US』 ;
- 单引号内的特殊字符则仅为一般字符 (纯文本),如下所示: 『var=’lang is $LANG’』则『echo $var』可得『lang is $LANG』;

5.可用跳脱字符『 \ 』将特殊符号(如 [Enter], $, , 空格符, ‘等)变成一般字符;
6.在一串指令中,还需要藉由其他的指令提供的信息,可以使用反单引号『指令』或 『$(指令)』。特别注意,那个 ` 是键盘上方的数字键 1 左边那个按键,而不是单引号! 例如想要取得核心版本的设定: 『version=$(uname -r)』再『echo $version』可得『2.6.18-128.el5』;
7.若该变量为扩增变量内容时,则可用 “$变量名称” 或 ${变量} 累加内容,如下所示: 『PATH=”$PATH”:/home/bin』;
8.若该变量需要在其他子程序执行,则需要以 export 来使变量变成环境变量: 『export PATH』;
9.通常大写字符为系统默认变量,自行设定变量可以使用小写字符,方便判断 (纯粹依照使用者兴趣与嗜好) ;
10.取消变量的方法为使用 unset :『unset 变量名称』例如取消 myname 的设定: 『unset myname』;

底下让鸟哥举几个例子来让你试看看,就知道怎么设定好你的变量!
这里写图片描述
这里写图片描述这里写图片描述
什么是『子程序』呢?就是说,在我目前这个 shell 的情况下,去启用另一个新的 shell ,新的那个 shell 就是子程序!在一般的状态下,父程序的自定义变量是无法在子程序内使用的。但是透过 export 将变量变成环境变量后,就能够在子程序底下应用了!至于程序的相关概念, 我们会在第十七章程序管理当中提到的!
这里写图片描述
每个 Linux 都能够拥有多个核心版本,且几乎 distribution 的核心版本都不相同。以 CentOS 5.3 (未更新前) 为例,他的预设核心版本是 2.6.18-128.el5 ,所以核心模块目录在 /lib/modules/2.6.18-128.el5/kernel/ 内。 也由于每个 distributions 的这个值都不相同,但是我们却可以利用 uname -r 这个指令先取得版本信息。所以,就可以透过上面指令当中的内含指令 uname -r 先取得版本输出到 cd … 那个指令当中,就能够顺利的进入目前核心的驱动程序所放置的目录!
其实上面的指令可以说是作了两次动作,亦即是:
1.先进行反单引号内的动作『uname -r』并得到核心版本为 2.6.18-128.el5;
2.将上述的结果带入原指令,故得指令为:『cd /lib/modules/2.6.18-128.el5/kernel/』;
这里写图片描述
较为重要的一些特殊符号的使用!例如单引号、双引号、跳脱字符、钱字号、反单引号等等!
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

11.2.3. 环境变量的功能: env与常见环境变量说明, set, export
目前我的 shell 环境中, 有多少默认的环境变量啊?我们可以利用两个在指令来查阅,分别是 env 与 export !

一、用 env 观察环境变量与常见环境变量说明
这里写图片描述
这里写图片描述
env 是 environment (环境) 的简写,上面的例子当中,是列出来所有的环境变量。 那么上面这些变量有些什么功用呢?底下我们就一个一个来分析分析!
• HOME
代表用户的家目录。
• SHELL
目前这个环境使用的 SHELL 是哪支程序? Linux 预设使用 /bin/bash 的!
• HISTSIZE
这个与『历史命令』有关,亦即是, 我们曾经下达过的指令可以被系统记录下来,而记录的『笔数』则是由这个值来设定的。
• MAIL
系统会去读取的邮件信箱档案 (mailbox)。
• PATH
就是执行文件搜寻的路径。
• LANG
就是语系数据
• RANDOM
『随机随机数』的变量!目前大多数的 distributions 都会有随机数生成器,那就是 /dev/random 这个档案。 我们可以透过这个随机数档案相关的变量 ($RANDOM) 来随机取得随机数值喔。在 BASH 的环境下,这个 RANDOM 变量的内容,介于 0~32767 之间,所以,你只要 echo $RANDOM 时,系统就会主动的随机取出一个介于 0~32767 的数值。利用 declare 宣告数值类型, 然后这样做就可以了:
这里写图片描述

二、用 set 观察所有变量 (含环境变量与自定义变量)
bash 可不只有环境变量,还有一些与 bash 操作接口有关的变量,以及用户自己定义的变量存在的。 那么这些变量如何观察呢?这个时候就得要使用 set 这个指令了。 set 除了环境变量之外, 还会将其他在 bash 内的变量通通显示出来!底下仅列出几个重要的内容:
这里写图片描述
这里写图片描述
一般来说,不论是否为环境变量,只要跟我们目前这个 shell 的操作接口有关的变量, 通常都会被设定为大写字符,也就是说,『基本上,在 Linux 预设的情况中,使用{大写的字母}来设定的变量一般为系统内定需要的变量』。

1.PS1:(提示字符的设定)
这是 PS1 (数字的 1 不是英文字母),这个东西就是我们的『命令提示字符』! 当我们每次按下 [Enter] 按键去执行某个指令后,最后要再次出现提示字符时, 就会主动去读取这个变数值了。上头 PS1 内显示的是一些特殊符号,这些特殊符号可以显示不同的信息, 每个 distributions 的 bash 默认的 PS1 变量内容可能有些许的差异,不要紧,『习惯你自己的习惯』就好了。 你可以用 man bash (注3)去查询一下 PS1 的相关说明,以理解底下的一些符号意义。
- \d :可显示出『星期 月 日』的日期格式,如:”Mon Feb 2” ;
- \H :完整的主机名。举例来说,鸟哥的练习机为『www.vbird.tsai』 ;
- \h :仅取主机名在第一个小数点之前的名字,如鸟哥主机则为『www』后面省略 ;
- \t :显示时间,为 24 小时格式的『HH:MM:SS』 ;
- \T :显示时间,为 12 小时格式的『HH:MM:SS』 ;
- \A :显示时间,为 24 小时格式的『HH:MM』 ;
- \@ :显示时间,为 12 小时格式的『am/pm』样式 ;
- \u :目前使用者的账号名称,如『root』;
- \v :BASH 的版本信息,如鸟哥的测试主板本为 3.2.25(1),仅取『3.2』显示 ;
- \w :完整的工作目录名称,由根目录写起的目录名称。但家目录会以 ~ 取代;
- \W :利用 basename 函数取得工作目录名称,所以仅会列出最后一个目录名。
- \# :下达的第几个指令。
- \$ :提示字符,如果是 root 时,提示字符为 # ,否则就是 $ ;

好了,让我们来看看 CentOS 预设的 PS1 内容:『[\u@\h \W]\$ 』,现在你知道那些反斜杠后的数据意义了!那个反斜杠后的数据为 PS1 的特殊功能,与 bash 的变量设定没关系!不要搞混了! 那你现在知道为何你的命令提示字符是:『 [root@www ~]# 』了吧? 好了,那么假设我想要有类似底下的提示字符:
[root@www /home/dmtsai 16:50 #12]#
那个 # 代表第 12 次下达的指令。那么应该如何设定 PS1 呢?可以这样啊:
这里写图片描述

2.$:(关于本 shell 的 PID)
钱字号本身也是个变量!这个咚咚代表的是『目前这个 Shell 的线程代号』,亦即是所谓的 PID (Process ID)。 更多的程序观念,我们会在第四篇的时候提及。想要知道我们的 shell 的 PID ,就可以用:『 echo $$ 』即可!出现的数字就是你的 PID 号码。

3.?:(关于上个执行指令的回传值)
问号也是一个特殊的变数!在 bash 里面这个变量可重要的很! 这个变数是:『上一个执行的指令所回传的值』, 上面这句话的重点是『上一个指令』与『回传值』两个地方。当我们执行某些指令时, 这些指令都会回传一个执行后的代码。一般来说,如果成功的执行该指令, 则会回传一个 0 值,如果执行过程发生错误,就会回传『错误代码』才对!一般就是以非为 0 的数值来取代。 我们以底下的例子来看看:
这里写图片描述

4.OSTYPE, HOSTTYPE, MACHTYPE:(主机硬件与核心的等级)
我们在第零章、计算器概论内的 CPU 等级说明中谈过 CPU , 目前个人计算机的 CPU 主要分为 32/64 位,其中 32 位又可分为 i386, i586, i686,而 64 位则称为 x86_64。 由于不同等级的 CPU 指令集不太相同,因此你的软件可能会针对某些 CPU 进行优化,以求取较佳的软件性能。 所以软件就有 i386, i686 及 x86_64 之分。以目前 (2009) 的主流硬件来说,几乎都是 x86_64 的天下!

三、export: 自定义变量转成环境变量
谈了 env 与 set 现在知道有所谓的环境变量与自定义变量,这两者的差异在于『 该变量是否会被子程序所继续引用』!那么啥是父程序?子程序? 这就得要了解一下指令的下达行为了。 当你登入 Linux 并取得一个 bash 之后,你的 bash 就是一个独立的程序,被称为 PID 的就是。 接下来你在这个 bash 底下所下达的任何指令都是由这个 bash 所衍生出来的,那些被下达的指令就被称为子程序了。 我们可以用底下的图示来简单的说明一下父程序与子程序的概念:
这里写图片描述
如上所示,我们在原本的 bash 底下执行另一个 bash ,结果操作的环境接口会跑到第二个 bash 去(就是子程序), 那原本的 bash 就会在暂停的情况 (睡着了,就是 sleep)。整个指令运作的环境是实线的部分!若要回到原本的 bash 去, 就只有将第二个 bash 结束掉 (下达 exit 或 logout) 才行。更多的程序概念我们会在第四篇谈及,这里只要有这个概念即可。
这个程序概念与变量有啥关系啊?关系可大了!因为子程序仅会继承父程序的环境变量, 子程序不会继承父程序的自定义变量!所以你在原本 bash 的自定义变量在进入了子程序后就会消失不见, 一直到你离开子程序并回到原本的父程序后,这个变量才会又出现!
换个角度来想,也就是说,如果我能将自定义变量变成环境变量的话,那不就可以让该变量值继续存在于子程序了?没错!此时,那个 export 指令就很有用了!如你想要让该变量内容继续的在子程序中使用,那么就请执行:
这里写图片描述
这东西用在『分享自己的变量设定给后来呼叫的档案或其他程序』! 像常常在自己的主控文件后面呼叫其他附属档案(类似函式的功能),但是主控文件与附属档案内都有相同的变量名称, 若一再重复设定时,要修改也很麻烦,此时只要在原本的第一个档案内设定好『 export 变量 』, 后面所呼叫的档案就能够使用这个变量设定了!而不需要重复设定,这非常实用于 shell script 当中! 如果仅下达 export 而没有接变量时,那么此时将会把所有的『环境变量』秀出来!例如:
这里写图片描述

11.2.4. 影响显示结果的语系变量 (locale)
还记得我们在第五章里面提到的语系问题吗? 就是当我们使用 man command 的方式去查询某个数据的说明文件时,该说明档的内容可能会因为我们使用的语系不同而产生乱码。 另外,利用 ls 查询档案的时间时,也可能会有乱码出现在时间的部分。那个问题其实就是语系的问题。
目前大多数的 Linux distributions 已经都是支持日渐流行的万国码了,也都支持大部分的国家语系。 这有赖于 i18n (注4) 支援的帮助! 那么我们的 Linux 到底支持了多少的语系?这可以由 locale 这个指令来查询到!
这里写图片描述
正体中文语系至少支持了两种以上的编码,一种是目前还是很常见的 big5 ,另一种则是越来越热门的 utf-8 编码。 那么我们如何修订这些编码呢?其实可以透过底下这些变量的说:
这里写图片描述
基本上,你可以逐一设定每个与语系有关的变量数据,但事实上,如果其他的语系变量都未设定, 且你有设定 LANG 或者是 LC_ALL 时,则其他的语系变量就会被这两个变量所取代! 这也是为什么我们在 Linux 当中,通常说明仅设定 LANG 这个变量而已,因为他是最主要的设定变量! 好了,那么你应该要觉得奇怪的是,为什么在 Linux 主机的终端机接口 (tty1 ~ tty6) 的环境下,如果设定『 LANG=zh_TW.big5 』这个设定值生效后,使用 man 或者其他讯息输出时, 都会有一堆乱码,尤其是使用 ls -l 这个参数时?
因为在 Linux 主机的终端机接口环境下是无法显示像中文这么复杂的编码文字, 所以就会产生乱码了。也就是如此,我们才会必须要在 tty1 ~ tty6 的环境下, 加装一些中文化接口的软件,才能够看到中文!不过,如果你是在 MS Windows 主机以远程联机服务器的软件联机到主机的话,那么,其实文字接口确实是可以看到中文的。 此时反而你得要在 LANG 设定中文编码才好!
你当然可以让每个使用者自己去调整自己喜好的语系,但是整体系统默认的语系定义在哪里呢? 其实就是在 /etc/sysconfig/i18n !这个档案在 CentOS 5.x 的内容有点像这样:
这里写图片描述
因为在第四章的安装时选择的是中文语系安装画面, 所以这个档案默认就会使用中文编码。

11.2.5. 变量的有效范围:
变量也有使用的『范围』,我们在上头的 export 指令说明中,就提到了这个概念了。如果在跑程序的时候,有父程序与子程序的不同程序关系时, 则『变量』可否被引用与 export 有关。被 export 后的变量,我们可以称他为『环境变量』! 环境变量可以被子程序所引用,但是其他的自定义变量内容就不会存在于子程序中。
在学理方面,为什么环境变量的数据可以被子程序所引用呢?这是因为内存配置的关系!理论上是这样的:
• 当启动一个 shell,操作系统会分配一记忆区块给 shell 使用,此内存内之变量可让子程序取用;
• 若在父程序利用 export 功能,可以让自定义变量的内容写到上述的记忆区块当中(环境变量);
• 当加载另一个 shell 时 (亦即启动子程序,而离开原本的父程序了),子 shell 可以将父 shell 的环境变量所在的记忆区块导入自己的环境变量区块当中。

透过这样的关系,我们就可以让某些变量在相关的程序之间存在,以帮助自己更方便的操作环境! 不过要提醒的是,这个『环境变量』与『bash 的操作环境』意思不太一样,举例来说, PS1 并不是环境变量, 但是这个 PS1 会影响到 bash 的接口 (提示字符) !相关性要理清!

11.2.6. 变量键盘读取、数组与宣告: read, declare, array
我们上面提到的变量设定功能,都是由指令列直接设定的,那么,可不可以让用户能够经由键盘输入? 什么意思呢?是否记得某些程序执行的过程当中,会等待使用者输入 “yes/no” 之类的讯息啊? 在 bash 里面也有相对应的功能!此外,我们还可以宣告这个变量的属性, 例如:数组或者是数字等等的。底下就来看看吧!

一、read
要读取来自键盘输入的变量,就是用 read 这个指令了。这个指令最常被用在 shell script 的撰写当中, 想要跟使用者对谈?用这个指令就对了。关于 script 的写法,我们会在第十三章介绍,底下先来瞧一瞧 read 的相关语法!
这里写图片描述
read 之后不加任何参数,直接加上变量名称,那么底下就会主动出现一个空白行等待你的输入(如范例一)。 如果加上 -t 后面接秒数,例如上面的范例二,那么 30 秒之内没有任何动作时, 该指令就会自动略过了~如果是加上 -p ,在输入的光标前就会有比较多可以用的提示字符给我们参考!

二、declare / typeset
declare 或 typeset 是一样的功能,就是在『宣告变量的类型』。如果使用 declare 后面并没有接任何参数,那么 bash 就会主动的将所有的变量名称与内容通通叫出来,就好像使用 set 一样! 那么 declare 还有什么语法呢?看看先:
这里写图片描述
这里写图片描述
由于在默认的情况底下, bash 对于变量有几个基本的定义:
- 变量类型默认为『字符串』;
- bash 环境中的数值运算,预设最多仅能到达整数形态,所以 1/3 结果是 0;

如果需要非字符串类型的变量,那就得要进行变量的宣告才行! 底下继续来玩些其他的 declare 功能。
这里写图片描述
declare 也是个很有用的功能~尤其是当我们需要使用到底下的数组功能时, 他也可以帮我们宣告数组的属性!不过,老话一句,数组也是在 shell script 比较常用的! 比较有趣的是,如果你不小心将变量设定为『只读』,通常得要注销再登入才能复原该变量的类型了!

三、数组 (array) 变量类型
某些时候,我们必须使用数组来宣告一些变量, 数组对写数值程序的设计师来说,可是不能错过学习的重点之一! 那么要如何设定数组的变量与内容呢?在 bash 里头,数组的设定方式是: var[index]=content 。
意思是说,我有一个数组名为 var ,而这个数组的内容为 var[1]=小明, var[2]=大明, var[3]=好明 …. 等等,那个 index 就是一些数字,重点是用中括号 ([ ]) 来设定的。 目前我们 bash 提供的是一维数组。老实说,如果您不必写一些复杂的程序, 那么这个数组的地方,可以先略过,等到有需要再来学习即可!因为要制作出数组, 通常与循环或者其他判断式交互使用才有比较高的存在意义!
这里写图片描述
这里写图片描述
数组的变量类型比较有趣的地方在于『读取』,一般来说,建议直接以 ${数组} 的方式来读取,比较正确无误的!

11.2.7. 与文件系统及程序的限制关系: ulimit
想象一个状况:我的 Linux 主机里面同时登入了十个人,这十个人不知怎么搞的, 同时开启了 100 个档案,每个档案的大小约 10MBytes ,请问一下, 我的 Linux 主机的内存要有多大才够? 10*100*10 = 10000 MBytes = 10GBytes … 系统不挂点才有鬼哩!为了要预防这个情况的发生,所以我们的 bash 是可以『限制用户的某些系统资源』的,包括可以开启的档案数量, 可以使用的 CPU 时间,可以使用的内存总量等等。如何设定?用 ulimit !
这里写图片描述
这里写图片描述
这里写图片描述

还记得我们在第八章 Linux 磁盘文件系统里面提到过,单一 filesystem 能够支持的单一档案大小与 block 的大小有关。例如 block size 为 1024 byte 时,单一档案可达 16GB 的容量。但是,我们可以用 ulimit 来限制使用者可以建立的档案大小! 利用 ulimit -f 就可以来设定了!例如上面的范例二,要注意单位!单位是 Kbytes。 若改天你一直无法建立一个大容量的档案,记得瞧一瞧 ulimit 的信息!

11.2.8. 变量内容的删除、取代与替换:
变量除了可以直接设定来修改原本的内容之外,有没有办法透过简单的动作来将变量的内容进行微调呢?

一、变量内容的删除与取代
变量的内容可以很简单的透过几个咚咚来进行删除!我们使用 PATH 这个变量的内容来做测试好了。 请你依序进行底下的几个例子来玩玩,比较容易感受想要表达的意义:
这里写图片描述
他的重点可以用底下这张表格来说明:
这里写图片描述
这里写图片描述
这样了解了 # 的功能了吗?接下来让我们来看看底下的范例三!
这里写图片描述
因为在 PATH 这个变量的内容中,每个目录都是以冒号『:』隔开的, 所以要仍头删除掉目录就是介于斜线 (/) 到冒号 (:) 之间的数据!但是 PATH 中不止一个冒号 (:) ! 所以 # 与 ## 就分别代表:
• # :符合取代文字的『最短的』那一个;
• ##:符合取代文字的『最长的』那一个

那么如果想要『仍后面向前删除变量内容』呢? 这个时候就得使用百分比 (%) 符号了!来看看范例四怎么做!
这里写图片描述
这里写图片描述
由于我是想要由变量内容的后面向前面删除,而我这个变量内容最后面的结尾是『/root/bin』, 所以你可以看到上面我删除的数据最终一定是『bin』,亦即是『:bin』那个 代表通配符! 至于 % 与 %% 的意义其实与 # 及 ## 类似!
这里写图片描述
了解了删除功能后,接下来谈谈取代!
这里写图片描述
我们将这部份作个总结说明一下:
这里写图片描述

二、变量的测试与内容替换
在某些时刻我们常常需要『判断』某个变量是否存在,若变量存在则使用既有的设定,若变量不存在则给予一个常用的设定。 我们举底下的例子来说明好了,看看能不能较容易被你所理解!
这里写图片描述
在上面的范例中,重点在于减号『 - 』后面接的关键词!基本上你可以这样理解:
这里写图片描述
不过这还是有点问题!因为 username 可能已经被设定为『空字符串』了!果真如此的话,那你还可以使用底下的范例来给予 username 的内容成为 root !
这里写图片描述
在大括号内有没有冒号『 : 』的差别是很大的!加上冒号后,被测试的变量未被设定或者是已被设定为空字符串时, 都能够用后面的内容 (本例中是使用 root 为内容) 来替换与设定!除了这样的测试之外, 还有其他的测试方法,整理如下:
这里写图片描述
首先让我们来测试一下,如果旧变量 (str) 不存在时, 我们要给予新变量一个内容,若旧变量存在则新变量内容以旧变量来替换,结果如下:
这里写图片描述
关于减号 (-) 其实上面我们谈过了!这里的测试只是要让你更加了解,这个减号的测试并不会影响到旧变量的内容。 如果你想要将旧变量内容也一起替换掉的话,那么就使用等号 (=) !
这里写图片描述
那如果我只是想知道,如果旧变量不存在时,整个测试就告知我『有错误』,此时就能够使用问号『 ? 』的帮忙!
这里写图片描述
这里写图片描述
基本上这种变数的测试也能够透过 shell script 内的 if…then… 来处理, 不过既然 bash 有提供这么简单的方法来测试变量。

11.3. 命令别名与历史命令
我们知道在早期的 DOS 年代,清除屏幕上的信息可以使用 cls 来清除,但是在 Linux 里面, 我们则是使用 clear 来清除画面的。那么可否让 cls 等于 clear 呢?可以啊!用啥方法? link file 还是什么的?别急!底下我们介绍不用 link file 的命令别名来达成。那么什么又是历史命令? 曾经做过的举动我们可以将他记录下来!那就是历史命令。

11.3.1. 命令别名设定: alias, unalias
命令别名是一个很有趣的东西,特别是你的惯用指令特别长的时候!还有, 增设默认的选项在一些惯用的指令上面,可以预防一些不小心误杀档案的情况发生的时候! 举个例子来说,如果你要查询隐藏档,并且需要长的列出与一页一页翻看,那么需要下达『 ls -al | more 』这个指令,那可不可以使用 lm 来简化呢?当然可以,你可以在命令行下面下达:
这里写图片描述
立刻多出了一个可以执行的指令!这个指令名称为 lm ,且其实他是执行 ls -al | more !真是方便。不过, 要注意的是:『alias 的定义规则与变量定义规则几乎相同』, 所以你只要在 alias 后面加上你的 {『别名』=’指令 选项…’ }, 以后你只要输入 lm 就相当于输入了 ls -al|more 这一串指令!
另外,命令别名的设定还可以取代既有的指令!举例来说,我们知道 root 可以移除 (rm) 任何数据!所以当你以 root 的身份在进行工作时,需要特别小心, 但是总有失手的时候,那么 rm 提供了一个选项来让我们确认是否要移除该档案,那就是 -i 这个选项!所以,你可以这样做:
这里写图片描述
那么以后使用 rm 的时候,就不用太担心会有错误删除的情况了!这也是命令别名的优点! 那么如何知道目前有哪些的命令别名呢?就使用 alias !
这里写图片描述
由上面的资料当中,你也会发现一件事情,我们在第十章的 vim 程序编辑器里面提到 vi 与 vim 是不太一样的,vim 可以多作一些额外的语法检验与颜色显示,默认的 root 是单纯使用 vi 而已。 如果你想要使用 vi 就直接以 vim 来开启档案的话,使用『 alias vi=’vim’ 』这个设定即可。 至于如果要取消命令别名的话,那么就使用 unalias !例如要将刚刚的 lm 命令别名拿掉,就使用:
这里写图片描述
命令别名是『新创一个新的指令, 你可以直接下达该指令』的,至于变量则需要使用类似『 echo 』指令才能够呼叫出变量的内容!

11.3.2. 历史命令: history, HISTSIZE
前面我们提过 bash 有提供指令历史的服务!查询我们曾经下达过的指令就使用 history !
这里写图片描述
这里写图片描述
这里写图片描述
在正常的情况下,历史命令的读取与记录是这样的:
• 当我们以 bash 登入 Linux 主机之后,系统会主动的由家目录的 ~/.bash_history 读取以前曾经下过的指令,那么 ~/.bash_history 会记录几笔数据呢?这就与你 bash 的 HISTFILESIZE 这个变量设定值有关了!
• 假设我这次登入主机后,共下达过 100 次指令,『等我注销时, 系统就会将 101~1100 这总共 1000 笔历史命令更新到 ~/.bash_history 当中。』 也就是说,历史命令在我注销时,会将最近的 HISTFILESIZE 笔记录到我的纪录文件当中!
• 当然,也可以用 history -w 强制立刻写入的!那为何用『更新』两个字呢? 因为 ~/.bash_history 记录的笔数永远都是 HISTFILESIZE 那么多,旧的讯息会被主动的拿掉! 仅保留最新的!

我们可以利用相关的功能来帮我们执行命令:
这里写图片描述
历史命令用法可多了!如果我想要执行上一个指令, 除了使用上下键之外,我可以直接以『 !! 』 来下达上个指令的内容,此外, 我也可以直接选择下达第 n 个指令,『 !n 』来执行,也可以使用指令标头,例如 『 !vi 』来执行最近指令开头是 vi 的指令列!相当的方便而好用!
基本上 history 的用途很大的!但是需要小心安全的问题!尤其是 root 的历史纪录档案,这是 Cracker 的最爱!因为不小心的 root 会将很多的重要数据在执行的过程中会被纪录在 ~/.bash_history 当中,如果这个档案被解析的话,后果不堪吶!无论如何,使用 history 配合『 ! 』曾经使用过的指令下达是很有效率的一个指令下达方法!

一、同一账号同时多次登入的 history 写入问题
有些朋友在练习 linux 的时候喜欢同时开好几个 bash 接口,这些 bash 的身份都是 root 。 这样会有 ~/.bash_history 的写入问题吗?想一想,因为这些 bash 在同时以 root 的身份登入, 因此所有的 bash 都有自己的 1000 笔记录在内存中。因为等到注销时才会更新记录文件,所以啰, 最后注销的那个 bash 才会是最后写入的数据。如此一来其他 bash 的指令操作就不会被记录下来了 (其实有被记录,只是被后来的最后一个 bash 所覆盖更新了) 。
由于多重登入有这样的问题,所以很多朋友都习惯单一 bash 登入,再用工作控制 (job control, 第四篇会介绍) 来切换不同工作! 这样才能够将所有曾经下达过的指令记录下来,也才方便未来系统管理员进行指令的 debug !

二、无法记录时间
历史命令还有一个问题,那就是无法记录指令下达的时间。由于这 1000 笔历史命令是依序记录的, 但是并没有记录时间,所以在查询方面会有一些不方便。如果读者们有兴趣,其实可以透过 ~/.bash_logout 来进行 history 的记录,并加上 date 来增加时间参数,也是一个可以应用的方向!

11.4. Bash shell 的操作环境
是否记得我们登入主机的时候,屏幕上头会有一些说明文字,告知我们的 Linux 版本啊什么的, 还有,登入的时候我们还可以给予用户一些讯息或者欢迎文字。此外, 我们习惯的环境变量、命令别名等等的,是否可以登入就主动的帮我设定好? 这些都是需要注意的。另外,这些设定值又可以分为系统整体设定值与各人喜好设定值, 仅是一些档案放置的地点不同!

11.4.1. 路径与指令搜寻顺序
指令运作的顺序可以这样看:
1. 以相对/绝对路径执行指令,例如『 /bin/ls 』或『 ./ls 』;
2. 由 alias 找到该指令来执行;
3. 由 bash 内建的 (builtin) 指令来执行;
4. 透过 $PATH 这个变量的顺序搜寻到的第一个指令来执行。

举例来说,你可以下达 /bin/ls 及单纯的 ls 看看,会发现使用 ls 有颜色但是 /bin/ls 则没有颜色。 因为 /bin/ls 是直接取用该指令来下达,而 ls 会因为『 alias ls=’ls –color=tty’ 』这个命令别名而先使用! 如果想要了解指令搜寻的顺序,其实透过 type -a ls 也可以查询的到!上述的顺序最好先了解!
这里写图片描述
这里写图片描述

11.4.2. bash 的进站与欢迎讯息: /etc/issue, /etc/motd
bash 也有进站画面与欢迎讯息喔? 还记得在终端机接口 (tty1 ~ tty6) 登入的时候,会有几行提示的字符串吗?那就是进站画面!在 /etc/issue 里面!先来看看:
这里写图片描述
以完全未更新过的 CentOS 5.3 作为范例,里面默认有三行,较有趣的地方在于 \r 与 \m。 就如同 $PS1 这变量一样,issue 这个档案的内容也是可以使用反斜杠作为变量取用!你可以 man issue 配合 man mingetty 得到底下的结果:
这里写图片描述
这里写图片描述
这里写图片描述
你要注意的是,除了 /etc/issue 之外还有个 /etc/issue.net ,这个是提供给 telnet 这个远程登录程序用的。当我们使用 telnet连接主机时,主机的登入画面就会显示 /etc/issue.net 而不是 /etc/issue ! 至于如果您想要让使用者登入后取得一些讯息,例如您想要让大家都知道的讯息, 那么可以将讯息加入 /etc/motd 里面去 !例如:当登入后,告诉登入者, 系统将会在某个固定时间进行维护工作,可以这样做:
这里写图片描述
那么当你的使用者(包括所有的一般账号与 root)登入主机后,就会显示这样的讯息出来:
这里写图片描述

11.4.3. 环境配置文件: login, non-login shell, /etc/profile, ~/.bash_profile, source, ~/.bashrc
怎么我们什么动作都没有进行,但是一进入 bash 就取得一堆有用的变量了? 这是因为系统有一些环境配置文件案的存在,让 bash 在启动时直接读取这些配置文件,以规划好 bash 的操作环境了! 而这些配置文件又可以分为全体系统的配置文件以及用户个人偏好配置文件。要注意的是, 我们前几个小节谈到的命令别名、自定义的变数,在你注销 bash 后就会失效,所以你想要保留你的设定, 就得要将这些设定写入配置文件才行。

一、login 与 non-login shell
在开始介绍 bash 的配置文件前,我们一定要先知道的就是 login shell 与 non-login shell ! 重点在于有没有登入 (login) !
• login shell:取得 bash 时需要完整的登入流程的,就称为 login shell。举例来说,你要由 tty1 ~ tty6 登入,需要输入用户的账号与密码,此时取得的 bash 就称为『 login shell 』;
• non-login shell:取得 bash 接口的方法不需要重复登入的举动,举例来说,(1)你以 X window 登入 Linux 后, 再以 X 的图形化接口启动终端机,此时那个终端接口并没有需要再次的输入账号与密码,那个 bash 的环境就称为 non-login shell了。(2)你在原本的 bash 环境下再次下达 bash 这个指令,同样的也没有输入账号密码, 那第二个 bash (子程序) 也是 non-login shell 。
login shell 其实只会读取这两个配置文件:
1. /etc/profile:这是系统整体的设定,你最好不要修改这个档案;
2. ~/.bash_profile 或 ~/.bash_login 或 ~/.profile:属于使用者个人设定,你要改自己的数据,就写入这里!

二、/etc/profile (login shell 才会读)
你可以使用 vim 去阅读一下这个档案的内容。这个配置文件可以利用使用者的标识符 (UID) 来决定很多重要的变量数据, 这也是每个使用者登入取得 bash 时一定会读取的配置文件 ! 所以如果你想要帮所有使用者设定整体环境,那就是改这里!不过,没事还是不要随便改这个档案。 这个档案设定的变量主要有:
• PATH:会依据 UID 决定 PATH 变量要不要含有 sbin 的系统指令目录;
• MAIL:依据账号设定好使用者的 mailbox 到 /var/spool/mail/账号名;
• USER:根据用户的账号设定此一变量内容;
• HOSTNAME:依据主机的 hostname 指令决定此一变量内容;
• HISTSIZE:历史命令记录笔数。CentOS 5.x 设定为 1000 ;

/etc/profile 可不止会做这些事而已,他还会去呼叫外部的设定数据!在 CentOS 5.x 默认的情况下, 底下这些数据会依序的被呼叫进来:

• /etc/inputrc
其实这个档案并没有被执行!/etc/profile 会主动的判断使用者有没有自定义输入的按键功能,如果没有的话, /etc/profile 就会决定设定『INPUTRC=/etc/inputrc』这个变量!此一档案内容为 bash 的热键、[tab]要不要有声音等等的数据! 因为觉得 bash 预设的环境已经很棒了,所以不建议修改这个档案!

• /etc/profile.d/*.sh
其实这是个目录内的众多档案!只要在 /etc/profile.d/ 这个目录内且扩展名为 .sh ,另外,使用者能够具有 r 的权限, 那么该档案就会被 /etc/profile 呼叫进来。在 CentOS 5.x 中,这个目录底下的档案规范了 bash 操作接口的颜色、 语系、ll 与 ls 指令的命令别名、vi 的命令别名、which 的命令别名等等。如果你需要帮所有使用者设定一些共享的命令别名时, 可以在这个目录底下自行建立扩展名为 .sh 的档案,并将所需要的数据写入即可!

• /etc/sysconfig/i18n
这个档案是由 /etc/profile.d/lang.sh 呼叫进来的!这也是我们决定 bash 预设使用何种语系的重要配置文件! 档案里最重要的就是 LANG 这个变量的设定!

反正你只要记得,bash 的 login shell 情况下所读取的整体环境配置文件其实只有 /etc/profile,但是 /etc/profile 还会呼叫出其他的配置文件,所以让我们的 bash 操作接口发的非常的友善!

三、~/.bash_profile (login shell 才会读)
bash 在读完了整体环境设定的 /etc/profile 并藉此呼叫其他配置文件后,接下来则是会读取使用者的个人配置文件。 在 login shell 的 bash 环境中,所读取的个人偏好配置文件其实主要有三个,依序分别是:
1. ~/.bash_profile
2. ~/.bash_login
3. ~/.profile

其实 bash 的 login shell 设定只会读取上面三个档案的其中一个, 而读取的顺序则是依照上面的顺序。也就是说,如果 ~/.bash_profile 存在,那么其他两个档案不论有无存在,都不会被读取。 如果 ~/.bash_profile 不存在才会去读取 ~/.bash_login,而前两者都不存在才会读取 ~/.profile 的意思。 会有这么多的档案,其实是因应其他 shell 转换过来的使用者的习惯而已。 先让我们来看一下 root 的 /root/.bash_profile 的内容是怎样呢?
这里写图片描述
这个档案内有设定 PATH 这个变量!而且还使用了 export 将 PATH 变成环境变量! 由于 PATH 在 /etc/profile 当中已经设定过,所以在这里就以累加的方式增加用户家目录下的 ~/bin/ 为额外的执行文件放置目录。这也就是说,你可以将自己建立的执行档放置到你自己家目录下的 ~/bin/ 目录! 那就可以直接执行该执行档而不需要使用绝对/相对路径来执行该档案。
这个档案的内容比较有趣的地方在于 if … then … 那一段!那一段程序代码我们会在第十三章 shell script 谈到,假设你现在是看不懂的。 该段的内容指的是『判断家目录下的 ~/.bashrc 存在否,若存在则读入 ~/.bashrc 的设定』。 bash 配置文件的读入方式比较有趣,主要是透过一个指令『 source 』来读取的! 也就是说 ~/.bash_profile 其实会再呼叫 ~/.bashrc 的设定内容!最后,我们来看看整个 login shell 的读取流程:
这里写图片描述
实线的方向是主线流程,虚线的方向则是被呼叫的配置文件!从上面我们也可以清楚的知道,在 CentOS 的 login shell 环境下,最终被读取的配置文件是『 ~/.bashrc 』这个档案!所以,你当然可以将自己的偏好设定写入该档案即可。 底下我们还要讨论一下 source 与 ~/.bashrc !

四、source :读入环境配置文件的指令
由于 /etc/profile 与 ~/.bash_profile 都是在取得 login shell 的时候才会读取的配置文件,所以, 如果你将自己的偏好设定写入上述的档案后,通常都是得注销再登入后,该设定才会生效。那么,能不能直接读取配置文件而不注销登入呢? 可以的!那就得要利用 source 这个指令了!
这里写图片描述
这里写图片描述
利用 source 或小数点 (.) 都可以将配置文件的内容读进来目前的 shell 环境中! 举例来说,我修改了 ~/.bashrc ,那么不需要注销,立即以 source ~/.bashrc 就可以将刚刚最新设定的内容读进来目前的环境中!还有,包括 ~/bash_profile 以及 /etc/profile 的设定中, 很多时候也都是利用到这个 source (或小数点) 的功能!
有没有可能会使用到不同环境配置文件的时候?有啊! 最常发生在一个人的工作环境分为多种情况的时候了!举个例子来说,在大型主机中, 常常需要负责两到三个不同的案子,每个案子所需要处理的环境变量设定并不相同, 那么就将这两三个案子分别编写属于该案子的环境变量配置文件案,当需要该环境时,就直接『 source 变量文件 』,如此一来,环境变量的设定就变的更简便而灵活了!

五、~/.bashrc (non-login shell 会读)
谈完了 login shell 后,那么 non-login shell 这种非登入情况取得 bash 操作接口的环境配置文件又是什么? 当你取得 non-login shell 时,该 bash 配置文件仅会读取 ~/.bashrc 而已!那么预设的 ~/.bashrc 内容是如何?
这里写图片描述
特别注意一下,由于 root 的身份与一般使用者不同,这是以 root 的身份取得上述的数据, 如果是一般使用者的 ~/.bashrc 会有些许不同。看一下,你会发现在 root 的 ~/.bashrc 中其实已经规范了较为保险的命令别名了。 此外,咱们的 CentOS 5.x 还会主动的呼叫 /etc/bashrc 这个档案!为什么需要呼叫 /etc/bashrc 呢? 因为 /etc/bashrc 帮我们的 bash 定义出底下的数据:
• 依据不同的 UID 规范出 umask 的值;
• 依据不同的 UID 规范出提示字符 (就是 PS1 变量);
• 呼叫 /etc/profile.d/*.sh 的设定;

你要注意的是,这个 /etc/bashrc 是 CentOS 特有的 (其实是 Red Hat 系统特有的),其他不同的 distributions 可能会放置在不同的档名就是了。由于这个 ~/.bashrc 会呼叫 /etc/bashrc 及 /etc/profile.d/*.sh , 所以,万一你没有 ~/.bashrc (可能自己不小心将他删除了),那么你会发现你的 bash 提示字符可能会变成这个样子:
这里写图片描述
这是正常的,因为你并没有呼叫 /etc/bashrc 来规范 PS1 变量!而且这样的情况也不会影响你的 bash 使用。 如果你想要将命令提示字符捉回来,那么可以复制 /etc/skel/.bashrc 到你的家目录,再修订一下你所想要的内容, 并使用 source 去呼叫 ~/.bashrc ,那你的命令提示字符就会回来!

六、其他相关配置文件
事实上还有一些配置文件可能会影响到你的 bash 操作的,底下就来谈一谈:

• /etc/man.config
这个档案乍看之下好像跟 bash 没相关性,但是对于系统管理员来说, 却也是很重要的一个档案!这的档案的内容『规范了使用 man 的时候, man page 的路径到哪里去寻找!』所以说的简单一点,这个档案规定了下达 man 的时候,该去哪里查看数据的路径设定!
那么什么时候要来修改这个档案呢?如果你是以 tarball 的方式来安装你的数据,那么你的 man page 可能会放置在 /usr/local/softpackage/man 里头,那个 softpackage 是你的套件名称, 这个时候你就得以手动的方式将该路径加到 /etc/man.config 里头,否则使用 man 的时候就会找不到相关的说明档。
事实上,这个档案内最重要的其实是 MANPATH 这个变量设定! 我们搜寻 man page 时,会依据 MANPATH 的路径去分别搜寻!另外,要注意的是, 这个档案在各大不同版本 Linux distributions 中,档名都不太相同,例如 CentOS 用的是 /etc/man.config ,而 SuSE 用的则是 /etc/manpath.config , 可以利用 [tab] 按键来进行文件名的补齐!

•~/.bash_history
预设的情况下, 我们的历史命令就记录在这里!而这个档案能够记录几笔数据,则与 HISTFILESIZE 这个变数有关。每次登入 bash 后,bash 会先读取这个档案,将所有的历史指令读入内存, 因此,当我们登入 bash 后就可以查知上次使用过哪些指令。

• ~/.bash_logout
这个档案则记录了『当我注销 bash 后,系统再帮我做完什么动作后才离开』的意思。 你可以去读取一下这个档案的内容,预设的情况下,注销时, bash 只是帮我们清掉屏幕的讯息而已。 不过,你也可以将一些备份或者是其他你认为重要的工作写在这个档案中 (例如清空暂存盘), 那么当你离开 Linux 的时候,就可以解决一些烦人的事情!

11.4.4. 终端机的环境设定: stty, set
我们在第五章首次登入 Linux 时就提过,可以在 tty1 ~ tty6 这六个文字接口的终端机 (terminal) 环境中登入,登入的时候我们可以取得一些字符设定的功能! 举例来说,我们可以利用退格键 (backspace) 来删除命令行上的字符, 也可以使用 [ctrl]+c 来强制终止一个指令的运行,当输入错误时,就会有声音跑出来警告。这是怎么办到的呢?因为登入终端机的时候,会自动的取得一些终端机的输入环境的设定! 事实上,目前我们使用的 Linux distributions 都帮我们作了最棒的使用者环境了, 所以大家可以不用担心操作环境的问题。不过,在某些 Unix like 的机器中,还是可能需要动用一些手脚, 才能够让我们的输入比较快乐。举例来说,利用 [backspace] 删除,要比利用 [Del] 按键来的顺手! 但是某些 Unix 偏偏是以 [del] 来进行字符的删除!所以,这个时候就可以动动手脚。 那么如何查阅目前的一些按键内容呢?可以利用 stty (setting tty 终端机的意思) ! stty 也可以帮助设定终端机的输入按键代表意义!
这里写图片描述
这里写图片描述
我们可以利用 stty -a 来列出目前环境中所有的按键列表,在上头的列表当中,需要注意的是特殊字体那几个, 此外,如果出现 ^ 表示 [Ctrl] 那个按键的意思。举例来说, intr = ^C 表示利用 [ctrl] + c 来达成的。几个重要的代表意义是:
• eof : End of file 的意思,代表『结束输入』; ^D
• erase : 向后删除字符; ^?
• intr : 送出一个 interrupt (中断) 的讯号给目前正在 run 的程序; ^C
• kill : 删除在目前指令列上的所有文字; ^U
• quit : 送出一个 quit 的讯号给目前正在 run 的程序; ^\
• start : 在某个程序停止后,重新启动他的 output ;^Q
• stop : 停止目前屏幕的输出; ^S
• susp : 送出一个 terminal stop 的讯号给正在 run 的程序;^Z

在第五章讲过几个 Linux 热键就是这个 stty 设定值内的 intr / eof 。至于删除字符,就是 erase 那个设定值! 如果你想要用 [ctrl]+h 来进行字符的删除,那么可以下达:
这里写图片描述
那么从此之后,你的删除字符就得要使用 [ctrl]+h ,按下 [backspace] 则会出现 ^? 字样! 如果想要回复利用 [backspace] ,就下达 stty erase ^? 即可! 至于更多的 stty 说明,记得参考一下 man stty 内容! 除了 stty 之外,其实我们的 bash 还有自己的一些终端机设定值!那就是利用 set 来设定的! 我们之前提到一些变量时,可以利用 set 来显示,除此之外,其实 set 还可以帮我们设定整个指令输出/输入的环境。 例如记录历史命令、显示错误内容等等。
这里写图片描述
这里写图片描述
另外,其实我们还有其他的按键设定功能!就是在前一小节提到的 /etc/inputrc 这个档案里面设定。
这里写图片描述
还有例如 /etc/DIR_COLORS* 与 /etc/termcap 等,也都是与终端机有关的环境配置文件案! 不过并不建议您修改 tty 的环境,这是因为 bash 的环境已经设定的很亲和了, 我们不需要额外的设定或者修改,否则反而会产生一些困扰。不过,写在这里的数据, 只是希望大家能够清楚的知道我们的终端机是如何进行设定的 ! 最后,我们将 bash 默认的组合键给他汇整如下:
这里写图片描述

11.4.5. 通配符与特殊符号
在 bash 的操作环境中还有一个非常有用的功能,那就是通配符 (wildcard) ! 我们利用 bash 处理数据就更方便了!底下我们列出一些常用的通配符:
这里写图片描述
利用通配符配合 ls 找档名看看:
这里写图片描述
除了通配符之外,bash 环境中的特殊符号有底下汇整的:
这里写图片描述
这里写图片描述
以上为 bash 环境中常见的特殊符号汇整!理论上,你的『档名』尽量不要使用到上述的字符!

11.5. 数据流重导向 (Redirection)
数据流重导向就是将某个指令执行后应该要出现在屏幕上的数据, 给他传输到其他的地方,例如档案或者是装置 (例如打印机之类的) !

11.5.1. 何谓数据流重导向?
这得要由指令的执行结果谈起!一般来说,如果你要执行一个指令,通常他会是这样的:
这里写图片描述
我们执行一个指令的时候,这个指令可能会由档案读入资料,经过处理之后,再将数据输出到屏幕上。 在上图当中, standard output 与 standard error output 分别代表『标准输出』与『标准错误输出』, 默认都是输出到屏幕上面的!

一、standard output 的 standard error output
简单的说,标准输出指的是『指令执行所回传的正确的讯息』,而标准错误输出可理解为『 指令执行失败后,所回传的错误讯息』。

数据流重导向可以将 standard output (简称 stdout) 与 standard error output (简称 stderr) 分别传送到其他的档案或装置去,而分别传送所用的特殊字符则如下所示:
1. 标准输入 (stdin) :代码为 0 ,使用 < 或 << ;
2. 标准输出 (stdout):代码为 1 ,使用 > 或 >> ;
3. 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;

因为该档案的建立方式是:
1. 该档案 (本例中是 ~/rootfile) 若不存在,系统会自动的将他建立起来,但是
2. 当这个档案存在的时候,那么系统就会先将这个档案内容清空,然后再将数据写入!
3. 也就是若以 > 输出到一个已存在的档案中,那个档案就会被覆盖掉!

那如果我想要将数据累加而不想要将旧的数据删除,利用两个大于的符号 (>>) 就好!你应该要改成『 ll / >> ~/rootfile 』即可。 如此一来,当 (1) ~/rootfile 不存在时系统会主动建立这个档案;(2)若该档案已存在, 则数据会在该档案的最下方累加进去!
那如果是 standard error output 的错误数据就透过 2> 及 2>> !同样是覆盖 (2>) 与累加 (2>>) 的特性!我们在刚刚才谈到 stdout 代码是 1 而 stderr 代码是 2 , 所以这个 2> 是很容易理解的,而如果仅存在 > 时,则代表预设的代码 1 !也就是说:

  • 1> :以覆盖的方法将『正确的数据』输出到指定的档案或装置上;
  • 1>>:以累加的方法将『正确的数据』输出到指定的档案或装置上;
  • 2>:以覆盖的方法将『错误的数据』输出到指定的档案或装置上;
  • 2>>:以累加的方法将『错误的数据』输出到指定的档案或装置上;

『 1>> 』以及『 2>> 』中间是没有空格的!当你以一般身份执行 find 这个指令的时候,由于权限的问题可能会产生一些错误信息。例如执行『 find / -name testing 』时,可能会产生类似『 find: /root: Permission denied 』之类的讯息。 例如底下这个范例:
这里写图片描述
由于 /home 底下还有我们之前建立的账号存在,那些账号的家目录你当然不能进入!所以就会有错误及正确数据了。 好了,那么假如我想要将数据输出到 list 这个档案中呢?执行『 find /home -name .bashrc > list 』 会发现 list 里面存了刚刚那个『正确』的输出数据, 至于屏幕上还是会有错误的讯息出现 !如果想要将正确的与错误的数据分别存入不同的档案中需要怎么做?
这里写图片描述
此时『屏幕上不会出现任何讯息』!

二、/dev/null 垃圾桶黑洞装置与特殊写法
如果我知道错误讯息会发生,所以要将错误讯息忽略掉而不显示或储存, 这个时候黑洞装置 /dev/null 就很重要了!这个 /dev/null 可以吃掉任何导向这个装置的信息!将上述的范例修订一下:
这里写图片描述
要将正确与错误数据通通写入同一个档案去,这个时候就得要使用特殊的写法了! 我们同样用底下的案例来说明:
这里写图片描述
上述表格第一行错误的原因是,由于两股数据同时写入一个档案,又没有使用特殊的语法, 此时两股数据可能会交叉写入该档案内,造成次序的错乱。所以虽然最终 list 档案还是会产生,但是里面的数据排列就会怪怪的,而不是原本屏幕上的输出排序。 至于写入同一个档案的特殊语法如上表所示,你可以使用 2>&1 也可以使用 &> !

三、standard input : < 与 <<
< 是『将原本需要由键盘输入的数据,改由档案内容来取代』的意思。 我们先由底下的 cat 指令操作来了解一下什么叫做『键盘输入』!
这里写图片描述
由于加入 > 在 cat 后,所以那个 catfile 会被主动的建立,而内容就是刚刚键盘上面输入的那两行数据了。 用纯文本文件取代键盘的输入,如下所示:
这里写图片描述
这里写图片描述
用在类似 mail 这种指令的使用上非常的有帮助。 << 代表的是『结束的输入字符』的意思!举例来讲:『我要用 cat 直接将输入的讯息输出到 catfile 中, 且当由键盘输入 eof 时,该次输入就结束』,那我可以这样做:
这里写图片描述
利用 << 右侧的控制字符,我们可以终止一次输入, 而不必输入 [crtl]+d 来结束!这对程序写作很有帮助!好了,那么为何要使用命令输出重导向呢?
• 屏幕输出的信息很重要,而且我们需要将他存下来的时候;
• 背景执行中的程序,不希望他干扰屏幕正常的输出结果时;
• 一些系统的例行命令 (例如写在 /etc/crontab 中的档案) 的执行结果,希望他可以存下来时;
• 一些执行命令的可能已知错误讯息时,想以『 2> /dev/null 』将他丢掉时;
• 错误讯息与正确讯息需要分别输出时。

11.5.2. 命令执行的判断依据: ; , &&, ||
很多指令我想要一次输入去执行,而不想要分次执行时,基本上你有两个选择, 一个是透过第十三章要介绍的 shell script 撰写脚本去执行,一种则是透过底下的介绍来一次输入多重指令!

一、cmd ; cmd (不考虑指令相关性的连续指令下达)
在指令与指令中间利用分号 (;) 来隔开,这样一来,分号前的指令执行完后就会立刻接着执行后面的指令了。

二、$?(指令回传值) 与 && 或 ||
如同上面谈到的,两个指令之间有相依性,而这个相依性主判断的地方就在于前一个指令执行的结果是否正确。 就是透过这个回传值! 再复习一次『若前一个指令执行的结果为正确,在 Linux 底下会回传一个 $? = 0 的值』。 那么我们怎么透过这个回传值来判断后续的指令是否要执行呢?这就得要藉由『 && 』及『 || 』的帮忙了!两个 & 之间是没有空格的!那个 | 则是 [Shift]+[] 的按键结果。
这里写图片描述
回到我们刚刚假想的情况,就是想要: (1)先判断一个目录是否存在; (2)若存在才在该目录底下建立一个档案。由于我们尚未介绍如何判断式 (test) 的使用,在这里我们使用 ls 以及回传值来判断目录是否存在! 让我们进行底下这个练习看看:
这里写图片描述
能不能自动判断,如果没有该目录就给予建立呢? 参考一下底下的例子先:
这里写图片描述
如果我想要建立 /tmp/abc/hehe 这个档案, 但我并不知道 /tmp/abc 是否存在,那该如何是好?试看看:
这里写图片描述
上面这个范例三总是会建立 /tmp/abc/hehe 的!不论 /tmp/abc 是否存在。 由于Linux 底下的指令都是由左往右执行的,所以范例三有几种结果我们来分析一下:
• (1)若 /tmp/abc 不存在故回传 $?≠0,则 (2)因为 || 遇到非为 0 的 $? 故开始 mkdir /tmp/abc,由于 mkdir /tmp/abc 会成功进行,所以回传 $?=0 (3)因为 && 遇到 $?=0 故会执行 touch /tmp/abc/hehe,最终 hehe 就被建立了;
• (1)若 /tmp/abc 存在故回传 $?=0,则 (2)因为 || 遇到 0 的 $? 不会进行,此时 $?=0 继续向后传,故 (3)因为 && 遇到 $?=0 就开始建立 /tmp/abc/hehe 了!最终 /tmp/abc/hehe 被建立起来。

整个流程图示如下:
这里写图片描述
上面这张图显示的两股数据中,上方的线段为不存在 /tmp/abc 时所进行的指令行为,下方的线段则是存在 /tmp/abc 所在的指令行为。如上所述,下方线段由于存在 /tmp/abc 所以导致 $?=0 ,让中间的 mkdir 就不执行了! 并将 $?=0 继续往后传给后续的 touch 去利用!在任何时刻你都可以拿上面这张图作为示意! 让我们来想想底下这个例题!
这里写图片描述
如果真要使用判断, 那么这个 && 与 || 的顺序就不能搞错。一般来说,假设判断式有三个,也就是: command1 && command2 || command3 。而且顺序通常不会变,因为一般来说, command2 与 command3 会放置肯定可以执行成功的指令。

11.6. 管线命令 (pipe)
管线命令与『连续下达命令』是不一样的 ! 假设我们想要知道 /etc/ 底下有多少档案,那么可以利用 ls /etc 来查阅,不过, 因为 /etc 底下的档案太多,此时,我们可以透过 less 指令的协助,利用:
这里写图片描述
如此一来,使用 ls 指令输出后的内容,就能够被 less 读取,并且利用 less 的功能,我们就能够前后翻动相关的信息了! 其实这个管线命令『 | 』仅能处理经由前面一个指令传来的正确信息,也就是 standard output 的信息,对于 stdandard error 并没有直接处理的能力。
这里写图片描述
在每个管线后面接的第一个数据必定是『指令』!而且这个指令必须要能够接受 standard input 的数据才行,这样的指令才可以是为『管线命令』,例如 less, more, head, tail 等都是可以接受 standard input 的管线命令。至于例如 ls, cp, mv 等就不是管线命令了!因为 ls, cp, mv 并不会接受来自 stdin 的数据。 也就是说,管线命令主要有两个比较需要注意的地方:
• 管线命令仅会处理 standard output,对于 standard error output 会予以忽略
• 管线命令必须要能够接受来自前一个指令的数据成为 standard input 继续处理才行。

11.6.1. 撷取命令: cut, grep
就是将一段数据经过分析后,取出我们所想要的。或者是经由分析关键词,取得我们所想要的那一行!要注意的是,一般来说,撷取讯息通常是针对『一行一行』来分析的, 并不是整篇讯息分析的:

一、cut
cut可以将一段讯息的某一段给他『切』出来, 处理的讯息是以『行』为单位!
这里写图片描述
这里写图片描述
这里写图片描述
cut 主要的用途在于将『同一行里面的数据进行分解!』最常使用在分析一些数据或文字数据的时候! 这是因为有时候我们会以某些字符当作分割的参数,然后来将数据加以切割,以取得我们所需要的数据。

二、grep
grep 则是分析一行讯息, 若当中有我们所需要的信息,就将该行拿出来:
这里写图片描述
这里写图片描述
grep 可以解析一行文字,取得关键词,若该行有存在关键词,就会整行列出来!

11.6.2. 排序命令: sort, uniq, wc
很多时候,我们都会去计算一次数据里头的相同型态的数据总数,举例来说, 使用 last 可以查得这个月份有登入主机者的身份。那么我可以针对每个使用者查出他们的总登入次数, 此时就得要排序与计算之类的指令来辅助了!

一、sort
sort 可以帮我们进行排序,而且可以依据不同的数据型态来排序! 此外,排序的字符与语系的编码有关,因此, 如果您需要排序时,建议使用 LANG=C 来让语系统一,数据排序比较好一些。
这里写图片描述
这里写图片描述
这里写图片描述
我们常常需要比较一些信息!

二、uniq
如果我排序完成了,想要将重复的资料仅列出一个显示,可以怎么做呢?
这里写图片描述
这里写图片描述
这个指令用来将『重复的行删除掉只显示一个』,举个例子来说, 你要知道这个月份登入你主机的用户有谁,而不在乎他的登入次数,那么就使用上面的范例, (1)先将所有的数据列出;(2)再将人名独立出来;(3)经过排序;(4)只显示一个! 由于这个指令是在将重复的东西减少,所以当然需要『配合排序过的档案』来处理啰!

三、wc
如果我想要知道 /etc/man.config 这个档案里面有多少字?多少行?多少字符的话, 其实可以利用 wc 这个指令来达成!他可以帮我们计算输出的讯息的整体数据!
这里写图片描述
wc 是相当有用的计算档案内容的一个工具组!举个例子来说, 当你要知道目前你的账号档案中有多少个账号时,就使用这个方法:『 cat /etc/passwd | wc -l 』啦!因为 /etc/passwd 里头一行代表一个使用者呀! 所以知道行数就晓得有多少的账号在里头了!而如果要计算一个档案里头有多少个字符时,就使用 wc -c 这个选项!

11.6.3. 双向重导向: tee

会将数据流整个传送给档案或装置,因此我们除非去读取该档案或装置, 否则就无法继续利用这个数据流。万一我想要将这个数据流的处理过程中将某段讯息存下来, 利用 tee 就可以:
这里写图片描述
tee 会同时将数据流分送到档案去与屏幕 (screen);而输出到屏幕的,其实就是 stdout ,可以让下个指令继续处理!
这里写图片描述
tee 可以让 standard output 转存一份到档案内并将同样的数据继续送到屏幕去处理! 这样除了可以让我们同时分析一份数据并记录下来之外,还可以作为处理一份数据的中间暂存盘记录之用!

11.6.4. 字符转换命令: tr, col, join, paste, expand
我们在 vim 程序编辑器当中,提到过 DOS 断行字符与 Unix 断行字符的不同,并且可以使用 dos2unix 与 unix2dos 来完成转换。好了,那么思考一下,是否还有其他常用的字符替代? 举例来说,要将大写改成小写,或者是将数据中的 [tab] 按键转成空格键?还有,如何将两篇讯息整合成一篇? 底下我们就来介绍一下这些字符转换命令在管线当中的使用方法:

一、tr
tr 可以用来删除一段讯息当中的文字,或者是进行文字讯息的替换!
这里写图片描述
这里写图片描述
其实这个指令也可以写在『正规表示法』里头!因为他也是由正规表示法的方式来取代数据的! 以上面的例子来说,使用 [] 可以设定一串字!也常常用来取代档案中的怪异符号 ! 例如上面第三个例子当中,可以去除 DOS 档案留下来的 ^M 这个断行的符号!这东西相当的有用!相信处理 Linux & Windows 系统中的人们最麻烦的一件事就是这个事情!亦即是 DOS 底下会自动的在每行行尾加入 ^M 这个断行符号!这个时候我们可以使用这个 tr 来将 ^M 去除! ^M 可以使用 \r 来代替之!

二、col
这里写图片描述
这里写图片描述
虽然 col 有他特殊的用途,不过,很多时候,他可以用来简单的处理将 [tab] 按键取代成为空格键! 例如上面的例子当中,如果使用 cat -A 则 [tab] 会以 ^I 来表示。 但经过 col -x 的处理,则会将 [tab] 取代成为对等的空格键!此外, col 经常被利用于将 man page 转存为纯文本文件以方便查阅的功能 !

三、join
join 看字面上的意义 (加入/参加) 就可以知道,他是在处理两个档案之间的数据, 而且,主要是在处理『两个档案当中,有 “相同数据” 的那一行,才将他加在一起』的意思。我们利用底下的简单例子来说明:
这里写图片描述
这里写图片描述
这个 join 在处理两个相关的数据文件时,就真的是很有帮助的! 例如上面的案例当中,我的 /etc/passwd, /etc/shadow, /etc/group 都是有相关性的, 其中 /etc/passwd, /etc/shadow 以账号为相关性,至于 /etc/passwd, /etc/group 则以所谓的 GID (账号的数字定义) 来作为他的相关性。根据这个相关性, 我们可以将有关系的资料放置在一起!这在处理数据可是相当有帮助的!
在使用 join 之前,你所需要处理的档案应该要事先经过排序 (sort) 处理 ! 否则有些比对的项目会被略过!

四、paste
相对于 join 必须要比对两个档案的数据相关性, paste 就直接『将两行贴在一起,且中间以 [tab] 键隔开』而已!简单的使用方法:
这里写图片描述

五、expand
这玩意儿就是在将 [tab] 按键转成空格键:
这里写图片描述
这里写图片描述
他会自动将 [tab] 转成空格键~所以,以上面的例子来说, 使用 cat -A 就会查不到 ^I 的字符。此外,因为 [tab] 最大的功能就是格式排列整齐! 我们转成空格键后,这个空格键也会依据我们自己的定义来增加大小~ 所以,并不是一个 ^I 就会换成 8 个空白! 此外,您也可以参考一下 unexpand 这个将空白转成 [tab] 的指令功能!

11.6.5. 分割命令: split
如果你有档案太大,导致一些携带式装置无法复制的问题,用 split 就对了! 他可以帮你将一个大档案,依据档案大小或行数来分割,就可以将大档案分割成为小档案了!
这里写图片描述
这里写图片描述
在 Linux 底下你要将档案分割的话,那么就使用 -b size 来将一个分割的档案限制其大小,如果是行数的话,那么就使用 -l line 来分割!

11.6.6. 参数代换: xargs
xargs 是在做什么的呢?就以字面上的意义来看, x 是加减乘除的乘号,args 则是 arguments (参数) 的意思,所以说,这个玩意儿就是在产生某个指令的参数的意思! xargs 可以读入 stdin 的数据,并且以空格符或断行字符作为分辨,将 stdin 的资料分隔成为 arguments 。 因为是以空格符作为分隔,所以,如果有一些档名或者是其他意义的名词内含有空格符的时候, xargs 可能就会误判了!
这里写图片描述
这里写图片描述
这里写图片描述
会使用 xargs 的原因是, 很多指令其实并不支持管线命令,因此我们可以透过 xargs 来提供该指令引用 standard input 之用 !
这里写图片描述

11.6.7. 关于减号 - 的用途
管线命令在 bash 的连续的处理程序中是相当重要的!另外,在 log file 的分析当中也是相当重要的一环, 所以请特别留意!另外,在管线命令当中,常常会使用到前一个指令的 stdout 作为这次的 stdin , 某些指令需要用到文件名 (例如 tar) 来进行处理时,该 stdin 与 stdout 可以利用减号 “-” 来替代, 举例来说:
这里写图片描述
上面这个例子是说:『我将 /home 里面的档案给他打包,但打包的数据不是纪录到档案,而是传送到 stdout; 经过管线后,将 tar -cvf - /home 传送给后面的 tar -xvf - 』。后面的这个 - 则是取用前一个指令的 stdout, 因此,我们就不需要使用 file 了!这是很常见的例子!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值