最近更新日期:2005/08/30
1. Bash shell
1.1 什么是 shell ? 1.2 系统的 shell 与 /etc/shells 功能 1.3 Bash shell 的功能 1.4 Bash shell 的内建命令: type 1.5 指令的下达 2. Shell 的变数功能 2.1 变数的取用与设定:echo, 变数设定规则, unset 2.2 变数的用途? 2.3 环境变数的功能: env, 一些重要的环境变数, set, export 2.4 语系档案的变数 (locale) 2.5 变数的有效范围: 2.6 变数键盘读取、阵列与宣告: read, declare, array 2.7 与档案系统及程序的限制关系: ulimit 2.8 其他额外变数功能 3. 命令别名与历史命令: 3.1 命令别名设定: alias, unalias 3.2 历史命令: history, HISTSIZE 4. Bash shell 使用环境: 4.1 绝对路径与相对路径 4.2 登录讯息显示资料: /etc/issue, /etc/motd 4.3 环境设定档: bashrc, ~/.bashrc, ~/.profile, profile...,/etc/inputrc, source 4.4 终端机的环境设定: stty, set 4.5 万用字元与特殊符号: 5. 资料流重导向 (redirecte) 5.1 何谓资料流重导向? 5.2 命令执行的判断依据: ; , &&, || 6. 管线命令 (pipe): 6.1 撷取命令: cut, grep 6.2 排序命令: sort, wc, uniq 6.3 双向重导向: tee 6.4 字元转换命令: tr, col, join, paste, expand 6.5 分割命令: split 6.6 参数代换: xargs 6.7 关于减号 - 的用途 7. 本章习题练习 Bash shell
我们在前面的
什么是 Linux 那个章节当中,提到了, 管理整个硬体的其实是核心 (kernel),那我们一般使用者 (user) 则是以 shell 来跟核心沟通~ 让核心达到我们所想要达到的工作目的。那么系统有多少 shell 可用呢? 为什么我们要使用 bash 啊?!底下分别来谈一谈喔!
什么是 Shell?
这应该是个蛮有趣的话题:‘
什么是 Shell ?’相信只要摸过电脑,对于作业系统 ( 不论是 Linux 、 Unix 或者是 Windows ) 有点概念的朋友们大多听过这个名词,因为只要有‘作业系统’那么就离不开 Shell 这个东西。不过,在讨论 Shell 之前,我们先来了解一下电脑的运作状况吧! 举个例子来说:
当你要电脑传输出来‘音乐’的时候,你的电脑需要什么东西呢?
图一、硬体、核心与使用者的相关性图示 图二、硬体、核心与使用者的相关性图示 基本上,替我们工作的是‘硬体’,而控制硬体的是‘核心’,再来,我们使用者乃是利用‘Shell’控制一些 kernel 提供的 ‘工具 (Utility)’来操控硬体替我们正确的工作。再进一步来说,由于 kernel 听不懂人类的语言,而人类也没有办法直接记得 kernel 的语言,所以两者的沟通就得藉由 shell 来支援了!( 其实早期的 DOS 的文字介面也是使用 shell 来沟通呀!那个 shell 的名称就叫做 command.com ,还记得吗? ^_^) 以字面上的意思来说, kernel 是‘核心’的意思,而 Shell 是‘壳’的意思,呵呵!也就是说, shell 是最外头的咚咚!而 kernel 乃是最内层的的咚咚啦!核心是作业系统的最底层的东西! 这个核心里头包括了各种的支援硬体的工具!当然啰,如果你的硬体太新,而你的 kernel 并没有支援的话,那么很抱歉,你的 Shell 能力再怎么强,也没有办法使硬体工作的! 这样可以了解了吗?呵呵!没错!使电脑主机工作的正是核心的任务,但是操作核心来替使用者工作的,却是 shell 喔!因此,有时候你的 shell 搞了老半天,硬体却不能工作的时候,请注意, 您的‘核心’是否正确呢?阿!扯远了!这是 kernel 章节才要说的东西。
系统的 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 的简单历史吧:第一个流行的 shell 是由 Steven Bourne 发展出来的,为了纪念他所以就称为 Bourne shell ,或直接简称为 sh !而后来另一个广为流传的 shell 是由柏克莱大学的 Bill Joy 设计依附于 BSD 版的 Unix 系统中的 shell ,这个 shell 的语法有点类似 C 语言,所以才得名为 C shell ,简称为 csh !由于在学术界 Sun 主机势力相当的庞大,而 Sun 主要是 BSD 的分支之一,所以 C shell 也是另一个很重要而且流传很广的 shell 之一 ( 因为太多的程式设计师使用的就是 C 语言啦! )!( 还记得我们在 Linux 是什么那一章提到的吧? Sun 公司的创始人就是 Bill Joy,而 BSD 最早就是 Bill Joy 发展出来的啊!)。 那么目前我们的 Linux (以 FC4 为例) 有多少我们可以使用的 shells 呢? 你可以检查一下 /etc/shells 这个档案,至少就有底下这几个可以用的 shells:
举例来说,某些 FTP 网站会去检查使用者的可用 shell ,而如果你不想要让这些使用者使用 FTP 以外的主机资源时,可能会给予该使用者一些怪怪的 shell,让使用者无法以其他服务登入主机。 这个时候,你就得将那些怪怪的 shell 写到 /etc/shells 当中了。举例来说,我们的 FC4 的 /etc/shells 里头就有个 /sbin/nologin 档案的存在,这个就是我们说的怪怪的 shell 啰~ 那么,再想一想,我这个使用者什么时候可以取得 shell 来工作呢?还有, 我这个使用者预设会取得哪一个 shell 啊?!还记得我们在 首次进入 Linux -- 以文字方式登入 那个章节当中提到的登入动作吧?当我登入的时候,系统就会给我一个 shell 让我来工作了。 而这个登入取得的 shell 就记录在 /etc/passwd 这个档案内!这个档案的内容是啥?
Bash shell 的功能
既然 /bin/bash 是 Linux 预设的 shell ,那么总是得了解一下这个玩意儿吧! BASH 是怎么一回事呢?这个 shell 是 GNU 计画中重要的工具软体之一,目前也是 GNU 作业系统中标准的 shell ,他主要相容于 sh ,并且依据一些使用者需求,而加强的 shell 版本,可以说目前几乎所有的 Linux distribution 都是使用 bash 作为管理核心的主要 shell !因此,不论您使用的是那个 distribution ,你都难逃需要学习 bash 的宿命啦!那么这个 shell 有什么好处,干嘛 Linux 要使用他作为预设的 shell 呢? BASH 主要的优点有底下几个:
Bash shell 的内建命令: type
我们在首次进入 Linux 章节当中,提到关于
Linux 的线上说明文件 部分,也就是 man page 的内容,那么 bash 有没有什么说明文件啊?开玩笑~ 这么棒的东西怎么可能没有说明文件!请您在 shell 的环境下,直接输入 man bash 瞧一瞧, 嘿嘿!不是盖的吧!让您看个几天几夜也无法看完的 bash 说明文件,可是很详尽的资料啊! ^_^
不过,在这个 man bash 所出现的 man page 当中,不知道您是否有察觉到,咦! 怎么这个说明文件里面有其他的档案说明啊?举例来说,那个 cd 指令的说明就在这个 man page 内? 然后我直接输入 man cd 时,怎么出现的画面中,最上方竟然出现一堆指令的介绍??这是怎么回事? 为了方便 shell 的操作,其实 bash 已经‘内建’了很多指令了,例如上面提到的 cd , 还有例如 umask 等等的指令,都是内建在 bash 当中的呢! 那我怎么知道这个指令是来自于外部指令(指的是其他非 bash 套件所提供的指令) 或是内建在 bash 当中的呢? 嘿嘿!利用 type 这个指令来观察即可!举例来说:
指令的下达
我们在
首次进入 Linux 一节当中,已经提到过在 shell 环境下的指令下达方式,不过,因为这个部分实在很重要,所以,我们还是再次的提醒一次!
Shell 的变数功能
在继续研究 BASH 之前,我们得要先就
变数 这个东西来讨论一番。 为什么要讨论变数呢?又,变数是啥玩意儿啊?!先来谈一谈国中数学好了,您是否依稀记得, 我们国中时候学过所谓的‘ y = ax + b ’这东西?其中, y 是变数, x 则是这个变数的内容啊! 讲的更简单一点,我们可以‘
用一个简单的 "字眼" 来取代另一个比较复杂或者是容易变动的资料’。这有什么好处啊?最大的好处就是‘方便!’。
如果以 Linux 主机的运作来说明好了,因为在主机里面有太多的资料需要进行存取了, 而这些资料都是一些服务所必须的,例如某个名为 dmtsai 的帐号,他的 mail 的存取路径预设是在 /var/spool/mail/dmtsai 、家目录预设在 /home/dmtsai 等等。那如果换了另外一个帐号呢? 假设另一个帐号名称为 vbird ,你猜他的邮件与家目录在哪?应该是在 /var/spool/mail/vbird 与 /home/vbird 对吧! 那么我们主机的邮件服务是否要记录好几个不同的路径啊?会不会太麻烦?这当然很麻烦啰~ 所以为了简化整个运作流程,我们就可以透过某个变数功能,让这个变数可以依据不同的使用者而变更内容, 如此一来,系统的邮件服务只要依据那个变数去取得所需要的资料即可,就不需要记录不同的路径啰。 举例来说,我们每个帐号的邮件信箱预设是以 MAIL 这个变数来进行存取的, 当 dmtsai 这个使用者登入时,他便会取得 MAIL 这个变数,而这个变数的内容其实就是 /var/spool/mail/dmtsai, 那如果 vbird 登入呢?他取得的 MAIL 这个变数的内容其实就是 /var/spool/mail/vbird 。 而我们使用信件读取指令 mail 来读取自己的邮件信箱时,嘿嘿,这支程式可以直接读取 MAIL 这个变数的内容, 就能够自动的分辨出属于自己的信箱信件啰!这样一来,设计程式的设计师就真的很方便的啦! 当然我们可以改变这些个变数,但是如果该变数是直接深植于套件当中, 那么当你修改了某些参数之后,嘿嘿!你的套件就必须要‘ 由原始码直接更新再编译’ 才行!这样似乎很麻烦,所以啰,变数真的是很方便的啦!
这些还都只是系统预设的变数的目的,如果是个人的设定方面的应用呢:例如你要写一个大型的 script (批次档)时,有些资料因为可能由于使用者习惯的不同而有差异,比如说路径好了,由于该路径在 script 被使用在相当多的地方,如果下次换了一部主机,都要修改 script 里面的所有路径,那么我一定会疯掉! 这个时候如果使用变数,而将该变数的定义写在最前面,后面相关的路径名称都以变数来取代, 嘿嘿!那么你只要修改一行就等于修改整篇 script 了!方便的很!所以,良好的程式设计师都会善用变数的定义! ( 这个部分我们在后续的 shell script 再次提及的!) 如果说的学理一点,那么由于在 Linux System 下面,所有的执行续都是需要一个执行码, 而就如同上面提到的,你‘ 真正以 shell 来跟 Linux 沟通,是在正确的登入 Linux 之后!’这个时候你就有一个 bash 的执行程序,也才可以真正的经由 bash 来跟系统沟通啰!而在进入 shell 之前,也正如同上面提到的,由于系统需要一些变数来提供他资料的存取(或者是一些环境的设定参数值, 例如是否要显示彩色等等的),所以就有一些所谓的‘ 环境变数’ 需要来读入系统中了!这些环境变数例如 PATH、HOME、MAIL、SHELL 等等,都是很重要的, 为了区别与自订变数的不同,环境变数通常以大写字元来表示呢! 好了,那么我们就简单的来对‘ 什么是变数’作个简单的定义好了: ‘ 变数就是以一组文字或符号等,来取代一些设定或者是一串保留的资料!’, 例如:我设定了‘myname’就是‘VBird’,所以当你读取 myname 这个变数的时候,系统自然就会知道!哈!那就是 VBird 啦!最简单的例子可以取 PATH 来说明!如果你对于‘ 相对路径与绝对路径’还有点印象的话, 那么应该晓得‘ 要下达正确的指令,应该需要指定路径与档名’才行!例如你的 ls 指令应该需要以‘/bin/ls’来下达指令才对,那么为何你在任意的路径下都可以执行 ls 呢?而不需要指定路径呢?这是因为系统已经预设了一些‘ 搜寻路径(PATH)’了, 所以当你需要执行一些指令的时候,系统就会依照该 PATH 的设定来进行指令的搜寻!而这个 PATH 就是所谓的变数了! 那么如何‘ 显示变数’呢?这就需要使用到 echo 这个指令啦! 变数的取用与设定:echo, 变数设定规则, unset
说的口沫横飞的,也不知道‘变数’与‘变数代表的内容’有啥关系? 当然啦,那我们就将‘变数’的‘内容’拿出来给您瞧瞧就好了。利用 echo 这个指令来取用变数, 但是,变数在被取用时,前面必须要加上 $ 才行,举例来说,要知道 PATH 的内容,该如何是好?
OK!现在我们知道了变数与变数内的之间的相关性了,好了,那么我要如何‘设定’或者是‘修改’ 某个变数的内容啊?!很简单啦!用‘等号(=)’连接变数与他的内容就好啦!举例来说: 我要将 myname 这个变数名称的内容设定为 VBird ,那么:
变数的用途
我们知道 PATH 这个变数是我们在执行指令的时候,所需要具备的指令搜寻目录资料, 没有他,我们就得要使用绝对路径来下达指令才行。当然,还有很多变数都有他特别的意义存在。 除此之外,‘
我为何需要设定变数’呢? 要跟大家介绍这个‘变数’,当然是因为他有相当程度的意义存在的啊! 底下就跟大家介绍一下,鸟哥设定变数的时机喔!
环境变数的功能
环境变数可以帮我们达到很多功能~包括家目录的变换啊、提示字元的显示啊、执行档搜寻的路径啊等等的, 还有很多很多啦!那么,既然环境变数有那么多的功能,问一下,目前我的 shell 环境中, 有多少变数啊?!呵呵!我们可以利用两个指令来查阅,分别是 env 与 export 呢!
语系档案的变数 (locale)
还记得我们在首次进入 Linux 那个章节里面提到的,关于语系编码的问题吗? 就是当我们使用 man command 的方式去查询某个资料的说明档时,该说明档的内容可能会因为我们使用的语系, 而产生一些乱码。另外,利用 ls 查询档案的时间时,也可能会有乱码出现在时间的部分。 那个问题其实就是语系的问题啦。
目前大多数的 Linux distributions 已经都是支援万国码,此外,也都支援大部分的语言语系了。 这有赖于 i18n 支援的帮助呢! 那么我们的 Linux 到底支援了多少的语系呢?这可以由 locale 这个指令来查询到喔!
因为在 Linux 主机的终端机介面下,那个环境是无法显示像中文这么复杂的编码的文字, 所以,就会产生乱码了。也就是如此,所以,我们才会必须要在 tty1 ~ tty6 的环境下, 加装一些中文化介面的软体,才能够看到中文啊!不过,如果您是在 Windows 主机以远端连线伺服器的软体连线到主机的话,那么,嘿嘿!其实文字介面确实是可以看到中文的。 所以,此时反而您得要在 LANG 设定中文编码才好呢! 无论如何,如果发生一些乱码的问题,那么设定系统里面保有的语系编码, 例如: en_US 或 en_US.utf8 等等的设定,应该就 OK 的啦!好了,那么系统预设支援多少种语系呢? 当我们使用 locale 时,系统是列出目前 Linux 主机内保有的语系档案, 这些语系档案都放置在: /usr/lib/locale/ 这个目录中。 但是,目前的这个 shell 环境所支援的语系,则是要看 SUPPORTED 这个变数才对喔! 那么,如果我想要修订系统的语系支援呢?可以修订 /etc/sysconfig/i18n 这个档案呢! 这个档案的内容有点像这样:
变数的有效范围
虾密??变数也有使用的‘范围’?没错啊~我们在上头的
export 指令说明中,就提到了这个概念了。如果在跑程式的时候,有父程序与子程序的不同程序关系时, 则‘变数’可否被引用是 export 有关。被 export 后的变数,我们可以称他为‘环境变数’! 环境变数可以被子程序所引用,但是其他的自订变数内容就不会存在于子程序中。也就是说:
我们自行设定的变数,只在目前这个 shell 环境当中存在, 在子程序中将不会存在此一变数。除非使用 export 将自订变数变成环境变数。
其实除了 shell 的父、子程序外,在脚本( scripts )的编写当中,由于有的软体会使用到 2 个以上的 scripts 做为一个完整的套件!也就是说,假如你有两支程式,一支为 scripts1.sh 以及 scripts2.sh ,而 scripts2.sh 会去引用 scripts1.sh 的变数,这个时候,嘿嘿!你在 scripts1.sh 当中设定的变数请‘ 千万记得以 export 设定’, 否则你的变数将无法在两个 scripts 之间互相被引用喔!当这个 scripts 执行完毕之后,刚刚在 scripts 当中设定的变数也就‘失效了!’。 其实,要了解不同程序之间变数的变换,应该要先了解‘程序’的概念比较好, 但是我们还没有讲到.....没关系~等你念到程序章节后,还可以再回来好好的看一看。 基本上,环境变数可以让子程序继续引用的原因,是因为:
变数键盘读取、阵列与宣告: read, array, declare
我们上面提到的变数设定功能,都是直接由指令列直接设定的,那么,可不可以让使用者能够经由键盘输入? 什么意思呢?是否记得某些程式执行的过程当中,会等待使用者输入 "yes/no" 之类的讯息啊!? 在 bash 里面也有相对应的功能喔!此外,我们还可以宣告这个变数的属性, 例如:阵列或者是数字等等的。底下就来看看吧!
与档案系统及程序的限制关系: ulimit
想像一个状况:我的 Linux 主机里面同时登入了十个人,这十个人不知怎么搞的, 同时开启了 100 个档案,每个档案的大小约 10MBytes ,请问一下, 我的 Linux 主机的记忆体要有多大才够? 10*100*10 = 10000 MBytes ~~ 老天爷,这样,系统不挂点才有鬼哩!为了要预防这个情况的发生,所以, 我们的 bash 是可以‘限制使用者的某些系统资源’的,包括可以开启的档案数量, 可以使用的 CPU 时间,可以使用的记忆体总量等等。如何设定?用 ulimit 吧!
额外的变数设定功能
刚刚我们提到了两种变数取用的方法,分别是这样:
虽然猛一看,觉得变数没有什么奇特的地方,但是,如果仔细瞧一瞧,嘿!一堆环境变数与系统资源方面的变数, 可是会影响到我们在 bash 里头是否能够顺利作业的呢!例如 PATH 啊、ulimit 之类的~ 所以,您还是得要了解变数这个玩意才行喔! ^_^
另外,几个不同的变数内容还可以进行判断呢! 举例来说,目前我需要用到两个变数,分别是 var 与 str , 那我想要针对 str 这个变数内容是否有设定成一个字串,亦即 "expr" 来决定 var 的内容。 那我可以使用什么方法来进行判断呢?如果您会写 shell script 的话, 直接用 shell script 就好了,如果不会写,那么我们就透过简单的变数判断吧!
根据上面这张表,我们来进行几个范例的练习吧! ^_^
命令别名与历史命令:
我们知道在早期的 DOS 年代,清除萤幕上的资讯可以使用 cls 来清除,但是在 Linux 里面, 我们则是使用 clear 来清除画面的。那么可否让 cls 等于 clear 呢?可以啊!用啥方法? link file 还是什么的?别急!底下我们介绍不用 link file 的命令别名来达成。那么什么又是历史命令? 曾经做过的举动我们可以将他记录下来喔!那就是历史命令啰~底下分别来谈一谈这两个玩意儿。
命令别名设定: alias, unalias
命令别名是一个很有趣的东西,特别是你的惯用指令特别长的时候!还有, 增设预设的属性在一些惯用的指令上面,可以预防一些不小心误杀档案的情况发生的时候! 举个例子来说,如果你要查询隐藏档,并且需要长的列出与一页一页翻看,那么需要下达‘
ls -al | more ’这个指令,我是觉得很烦啦! 要输入好几个单字!那可不可以使用 lm 来简化呢?!当然可以,你可以在命令列下面下达:
另外,命令别名的设定还可以取代既有的指令喔!举例来说,我们知道 root 可以移除( rm )任何资料!所以当你以 root 的身份在进行工作时,需要特别小心, 但是总有失手的时候,那么 rm 提供了一个参数来让我们确认是否要移除该档案,那就是 -i 这个参数!所以,你可以这样做:
历史命令:history
前面我们提过 bash 有提供指令历史的服务!那么如何查询我们曾经下达过的指令呢?就使用 history 啰!当然,如果觉得 histsory 要输入的字元太多太麻烦,可以使用命令别名来设定呢! 不要跟我说还不会设定呦! ^_^
那么 history 这个历史命令只可以让我查询命令而已吗?呵呵!当然不止啊! 我们可以利用相关的功能来帮我们执行命令呢!举例来说啰:
Bash Shell 使用环境:
是否记得我们登入主机的时候,萤幕上头会有一些说明文字,告知我们的 Linux 版本啊什么的, 还有,登入的时候,我们还可以给予使用者一些讯息或者欢迎文字呢。此外, 我们习惯的环境变数、命令别名等等的,是否可以登入就主动的帮我设定好? 这些都是需要来注意的。另外,这些设定值又可以分为系统整体设定值与各人喜好设定值, 仅是一些档案放置的地点不同啦!这我们后面也会来谈一谈的!
好了,我们知道在变数的设定规范当中,后输入的设定值可以取代先输入的设定值, 那么在我们登入 bash 的时候,这些设定档到底是如何读取的呢?他是这样读取的:
绝对路径与相对路径
这个议题说到快要烂掉了~从一开始到现在,这个绝对路径与相对路径的问题我们就提到不知道多少次了, 因为他实在很重要~这与 PATH 这个变数关系很大!老实说, 万一你的 PATH 没有设定完整的时候,下达指令就必须要以‘
一长列的指令连带根目录都要列出来 ’,呵呵那就是绝对路径的设定法啦! 基本上,这个‘
绝对路径’与‘
相对路径 ’的观念是很重要的!否则你将常常会找不到档案说! 所谓的‘绝对路径’就是以根目录开始写入到档案的一种命令写定方法,举例来说,我目前在 /home/test 这个 test 使用者的家目录中,我想要看看里面的 .bashrc 这个档案的资料,使用的是 more 这个指令,而这个指令在 /bin/more 当中,则正确的下达指令的方法为:
好了,由于系统预设并不主动搜寻目前目录下的执行档,那么你应该如何执行‘目前目录下的执行档’呢? 很简单呀!就是以相对路径的观念,由于‘ .. ’是上层,而‘ . ’是这一层,所以要执行这一层目录的命令就使用‘ ./command ’即可!例如你的 /usr/local/squid/bin 底下执行 squid 则可以写成:
登录讯息显示资料: /etc/issue, /etc/motd
还记得我们在终端机介面 (tty1 ~ tty6) 登入的时候,会有几行提示的字串吗? 那个字串写在哪里啊?呵呵!在 /etc/issue 里面啊!先来看看:
所以,如果您想要显示终端机的号码,就可以加上 /l 在 /etc/issue 档案内啰~就能够修改登入字元。 咦!但是还有个 /etc/issue.net 呢!这是啥?没啥啦!这个是提供给 telnet 这个远端登入程式用的。 当我们使用 telnet 连接到主机时,主机的登入画面就会显示 /etc/issue.net 而不是 /etc/issue 呢! 至于如果您想要让使用者登入后取得一些讯息,例如您想要让大家都知道的讯息, 那么可以将讯息加入 /etc/motd 里面去!例如:当登入后,告诉登入者, 系统将会在某个固定时间进行维护工作,可以这样做:
环境设定档: bashrc, ~/.bashrc, ~/.profile, profile...,/etc/inputrc, source
关于取得 bash 的环境变数等资料,其实可以有系统规划与各人喜好, 一般来说,建议使用者直接修改个人设定值即可,不需要更动到系统啦~ 底下我们分别来谈一谈几个有趣的设定档喔!要注意的是,在指令列输入的变数也好、命令别名也罢, 都是针对该次登入的设定而已,所以只要您一登出,那么上次的设定值就会不见去! 因此,我们需要有几个档案来帮助我们,每次登入的时候,就已经帮我们搞定了环境的设定啰!
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
网络快照,版权归“http://linux.vbird.org”网站所有。
此页面仅供个人学习之用
使用 set 除了会将系统的预设值秀出来之外,连带的所有的你自己设定的变数也会被秀出来! 同时需要注意的是,若当时有相当多人同时在线上的话,那么 你的变数只能给自己使用 ( 除非改的是系统的预设参数档,如 /etc/profile ),而不会干扰到别人的!就如同前面所说的, 由于你登入 Linux 之后会取得一个 PID ,而你的设定将只对这个 PID 与子程序有关!此外, 这次登入所进行的变数设定,如果没有更动到设定档, 那么这次设定的变数在下次登入时将被取消掉 ( 因为程序 PID 不见啰! ) !所以啰, 如果你想要你的变数每次都能在你登入的时候自动就设定好了,那么就必须将你的设定写入登入时载入的设定档! ( 更多的程序相关的说明,不要急~我们会在后面的 程序与资源管理 当中好好的提一提的! )
OK!OK!那么上头那些变数当中,有哪些是比较重要的?大概有这几个吧!
- PS1:(提示字元的设定)
这是 PS1 (数字的 1 不是英文字母!),这个东西就是我们的‘命令提示字元’啊! 当我们每次按下 [Enter] 按键去执行某个指令后,最后要再次出现提示字元时, 就会主动去读取这个变数值了。上头 PS1 内显示的是一些特殊符号,每个版本 bash 的 PSI 变数内的特殊符号可能有些许的差异, 你应该主动的以 man bash 去查询一下相关的变数。底下我列出 FC4 的环境下, 预设的 bash 的 PS1 变数内的特殊符号代表意义:
- /d :代表日期,格式为 Weekday Month Date,例如 "Mon Aug 1"
- /H :完整的主机名称。举例来说,鸟哥的练习机 linux.dmtsai.tw ,那么这个主机名称就是 linux.dmtsai.tw
- /h :仅取主机名称的第一个名字。以上述来讲,就是 linux 而已, .dmtsai.tw 被省略。
- /t :显示时间,为 24 小时格式,如: HH:MM:SS
- /T :显示时间,12 小时的时间格式!
- /A :显示时间,24 小时格式, HH:MM
- /u :目前使用者的帐号名称;
- /v :BASH 的版本资讯;
- /w :完整的工作目录名称。家目录会以 ~ 取代;
- /W :利用 basename 取得工作目录名称,所以仅会列出最后一个目录名。
- /# :下达的第几个指令。
- /$ :提示字元,如果是 root 时,提示字元为 # ,否则就是 $ 啰~
OK!所以,由预设的 PS1 内容为: '/[/u@/h /W/]/$ ' 就可以了解为何我们的提示字元会是: [root@linux ~]# 了吧!好了,那么假设我想要有类似底下的提示字元:
[root@linux /home/dmtsai 16:50 #12]#
,那个 # 代表第 12 次下达的指令。 那么应该如何设定 PS1 呢?可以这样啊:
___FCKpd___9
- $:(关于本 shell 的 PID)
其实这个咚咚代表的是‘目前这个 Shell 的执行绪代号’,亦即是所谓的 PID (Process ID)。 更多的程序观念,我们会在第四章的时候提及。想要知道我们的 shell 的 PID ,就可以: echo $$ 即可! - ?:(关于上个执行指令的回传码)
虾密?问号也是一个特殊的变数?没错!在 bash 里面这个变数可重要的很! 这个变数是:‘上个执行的指令所回传的值’, 上面这句话的重点是‘上一个指令’与‘回传值’两个地方。当我们执行某些指令时, 这些指令都会回传一个执行后的代码。一般来说,如果成功的执行该指令, 则会回传一个 0 值,如果执行过程发生错误,就会回传‘错误代码’才对!一般就是以非为 0 的数值来取代。 我们以底下的例子来看看:
___FCKpd___10
- OSTYPE, HOSTTYPE, MACHTYPE:(主机硬体与核心的等级)
这几个东西与程式的安装有关。我们在‘Linux 主机规划’ 里面提到过关于主机的等级方面的问题,当我们在安装软体的时候, 需要透过编译器来将原始码编译成为二进位的档案 (binary file)。但是, 我们可以针对硬体的配备来进行编译的最佳化,此时,这些参数就可以被用到了! 基本上,目前主要的 distribution 都是针对 i386 亦即最低等级的机器进行最佳化, 这样才能够安装在较高阶的机器上,如果以 686 的机型来最佳化, 那么,可就无法向下相容的喔!(早期的 OpenLinux 是针对 686 机器来释出软体, 所以,当时的 OpenLinux 是无法安装在 P-166 的机器上的。 )
自订变数转成环境变数: export
好了,上面我们环境变数也提过了,一些自订变数也提过了,那么,这两者有啥不同? 他的不同处,我们在
变数设定规则 当中稍微提过, 主要是由于变数可否被子程序所引用。
当你取得一个 bash 之后,亦即得到了一个程序了,但是若你再次的执行一次 bash ,那么你将进入‘子程序’,这个程序的概念我们在资源管理章节中再详谈,这里您先有个概念即可。 那么 由于您已经进入了该子程序,所以在父程序中的自订变数设定将不再继续的存在。 会存在子程序中的,仅有‘环境变数’。
换个角度来想,也就是说,如果我能将自订变数变成环境变数的话,那不就可以让该变数值继续存在于子程序了? 呵呵!没错!此时,那个 export 指令就很有用啦! 如您想要让该变数内容继续的在子程序中使用,那么就请执行:
当你取得一个 bash 之后,亦即得到了一个程序了,但是若你再次的执行一次 bash ,那么你将进入‘子程序’,这个程序的概念我们在资源管理章节中再详谈,这里您先有个概念即可。 那么 由于您已经进入了该子程序,所以在父程序中的自订变数设定将不再继续的存在。 会存在子程序中的,仅有‘环境变数’。
换个角度来想,也就是说,如果我能将自订变数变成环境变数的话,那不就可以让该变数值继续存在于子程序了? 呵呵!没错!此时,那个 export 指令就很有用啦! 如您想要让该变数内容继续的在子程序中使用,那么就请执行:
- export 变数
___FCKpd___11 |
语系档案的变数 (locale)
还记得我们在首次进入 Linux 那个章节里面提到的,关于语系编码的问题吗? 就是当我们使用 man command 的方式去查询某个资料的说明档时,该说明档的内容可能会因为我们使用的语系, 而产生一些乱码。另外,利用 ls 查询档案的时间时,也可能会有乱码出现在时间的部分。 那个问题其实就是语系的问题啦。
目前大多数的 Linux distributions 已经都是支援万国码,此外,也都支援大部分的语言语系了。 这有赖于 i18n 支援的帮助呢! 那么我们的 Linux 到底支援了多少的语系呢?这可以由 locale 这个指令来查询到喔!
中文语系至少支援了两种以上的编码,一种是目前还是很常见的 big5 ,另一种则是越来越热门的 utf-8 编码。 那么我们如何修订这些编码呢?其实可以透过底下这些变数的说:
基本上,你可以逐一设定每个与语系有关的变数资料,但事实上,如果其他的语系变数都未设定, 且您有设定 LANG 或者是 LC_ALL 时,则其他的语系变数就会被这两个变数所取代! 这也是为什么我们在 FC4 当中,通常仅设定 LANG 这个变数而已!因为他是最主要的设定变数。 好了,那么你应该要觉得奇怪的是,为什么在 Linux 主机的终端机介面 (tty1 ~ tty6) 的环境下,如果 LANG=zh_TW.big5 这个设定值生效后,使用 man 或者其他讯息输出时, 都会有一堆乱码,尤其是使用 ls -l 这个参数时?
因为在 Linux 主机的终端机介面下,那个环境是无法显示像中文这么复杂的编码的文字, 所以,就会产生乱码了。也就是如此,所以,我们才会必须要在 tty1 ~ tty6 的环境下, 加装一些中文化介面的软体,才能够看到中文啊!不过,如果您是在 Windows 主机以远端连线伺服器的软体连线到主机的话,那么,嘿嘿!其实文字介面确实是可以看到中文的。 所以,此时反而您得要在 LANG 设定中文编码才好呢!
无论如何,如果发生一些乱码的问题,那么设定系统里面保有的语系编码, 例如: en_US 或 en_US.utf8 等等的设定,应该就 OK 的啦!好了,那么系统预设支援多少种语系呢? 当我们使用 locale 时,系统是列出目前 Linux 主机内保有的语系档案, 这些语系档案都放置在: /usr/lib/locale/ 这个目录中。 但是,目前的这个 shell 环境所支援的语系,则是要看 SUPPORTED 这个变数才对喔!
那么,如果我想要修订系统的语系支援呢?可以修订 /etc/sysconfig/i18n 这个档案呢! 这个档案的内容有点像这样:
你可以在这个档案当中加入 LC_TIME 或者其他语系相关变数的设定内容, 也可以直接修改 LANG 那个变数即可啊! ^_^ 但,事实上,我们还可以透过个人的环境设定档来设定 LANG 呢! 如此一来,则不必修订系统的语系档案,比较安全啦!
目前大多数的 Linux distributions 已经都是支援万国码,此外,也都支援大部分的语言语系了。 这有赖于 i18n 支援的帮助呢! 那么我们的 Linux 到底支援了多少的语系呢?这可以由 locale 这个指令来查询到喔!
___FCKpd___12 |
___FCKpd___13 |
因为在 Linux 主机的终端机介面下,那个环境是无法显示像中文这么复杂的编码的文字, 所以,就会产生乱码了。也就是如此,所以,我们才会必须要在 tty1 ~ tty6 的环境下, 加装一些中文化介面的软体,才能够看到中文啊!不过,如果您是在 Windows 主机以远端连线伺服器的软体连线到主机的话,那么,嘿嘿!其实文字介面确实是可以看到中文的。 所以,此时反而您得要在 LANG 设定中文编码才好呢!
无论如何,如果发生一些乱码的问题,那么设定系统里面保有的语系编码, 例如: en_US 或 en_US.utf8 等等的设定,应该就 OK 的啦!好了,那么系统预设支援多少种语系呢? 当我们使用 locale 时,系统是列出目前 Linux 主机内保有的语系档案, 这些语系档案都放置在: /usr/lib/locale/ 这个目录中。 但是,目前的这个 shell 环境所支援的语系,则是要看 SUPPORTED 这个变数才对喔!
那么,如果我想要修订系统的语系支援呢?可以修订 /etc/sysconfig/i18n 这个档案呢! 这个档案的内容有点像这样:
___FCKpd___14 |
Tips: 假设你用 vi 编辑一个纯文字档,这个纯文字档在编辑的时候,是在 Windows 上面编辑的, 那么这个档案的预设编码应该是以 zh_TW.big5 所编辑的才对。但是,如果你的 shell 环境中, 却是使用 LANG=en_US 时,则当你编辑该档案时,就可能会看到‘乱码’, 或者输入的中文可能会变成‘乱码’了。此时,只要你离开 vi ,然后执行 LANG=zh_TW.big5 , 然后再重新以 vi 编辑该档案,呵呵!应该就能够看到中文啦!但是请注意, 这个方法当然不适用 tty1 ~ tty6 的环境,原因上面已经提过啰~ 仅适合以类似 putty 软体由 Windows 电脑连线到 linux 主机上的做业! |
变数的有效范围
虾密??变数也有使用的‘范围’?没错啊~我们在上头的
export 指令说明中,就提到了这个概念了。如果在跑程式的时候,有父程序与子程序的不同程序关系时, 则‘变数’可否被引用是 export 有关。被 export 后的变数,我们可以称他为‘环境变数’! 环境变数可以被子程序所引用,但是其他的自订变数内容就不会存在于子程序中。也就是说:
我们自行设定的变数,只在目前这个 shell 环境当中存在, 在子程序中将不会存在此一变数。除非使用 export 将自订变数变成环境变数。
其实除了 shell 的父、子程序外,在脚本( scripts )的编写当中,由于有的软体会使用到 2 个以上的 scripts 做为一个完整的套件!也就是说,假如你有两支程式,一支为 scripts1.sh 以及 scripts2.sh ,而 scripts2.sh 会去引用 scripts1.sh 的变数,这个时候,嘿嘿!你在 scripts1.sh 当中设定的变数请‘ 千万记得以 export 设定’, 否则你的变数将无法在两个 scripts 之间互相被引用喔!当这个 scripts 执行完毕之后,刚刚在 scripts 当中设定的变数也就‘失效了!’。
其实,要了解不同程序之间变数的变换,应该要先了解‘程序’的概念比较好, 但是我们还没有讲到.....没关系~等你念到程序章节后,还可以再回来好好的看一看。 基本上,环境变数可以让子程序继续引用的原因,是因为:
其实除了 shell 的父、子程序外,在脚本( scripts )的编写当中,由于有的软体会使用到 2 个以上的 scripts 做为一个完整的套件!也就是说,假如你有两支程式,一支为 scripts1.sh 以及 scripts2.sh ,而 scripts2.sh 会去引用 scripts1.sh 的变数,这个时候,嘿嘿!你在 scripts1.sh 当中设定的变数请‘ 千万记得以 export 设定’, 否则你的变数将无法在两个 scripts 之间互相被引用喔!当这个 scripts 执行完毕之后,刚刚在 scripts 当中设定的变数也就‘失效了!’。
其实,要了解不同程序之间变数的变换,应该要先了解‘程序’的概念比较好, 但是我们还没有讲到.....没关系~等你念到程序章节后,还可以再回来好好的看一看。 基本上,环境变数可以让子程序继续引用的原因,是因为:
- 当启动一个 shell ,作业系统分配一记忆区块给 shell 使用,此区域之变数可以让子程序存取;
- 利用 export 功能,可以让变数的内容写到上述的记忆区块当中(环境变数);
- 当载入另一个 shell 时 (亦即启动子程序,而离开原本的父程序了),子 shell 可以将父 shell 的环境变数所在的记忆区块导入自己的环境变数区块当中。
变数键盘读取、阵列与宣告: read, array, declare
我们上面提到的变数设定功能,都是直接由指令列直接设定的,那么,可不可以让使用者能够经由键盘输入? 什么意思呢?是否记得某些程式执行的过程当中,会等待使用者输入 "yes/no" 之类的讯息啊!? 在 bash 里面也有相对应的功能喔!此外,我们还可以宣告这个变数的属性, 例如:阵列或者是数字等等的。底下就来看看吧!
- read
要读取来自键盘输入的变数,就是用 read 这个指令了。这个指令最常被用在 shell script 的撰写当中, 以跟使用者进行对谈。关于 script 的写法,我们会在后面章节介绍,底下先来瞧一瞧 read 的相关语法吧!
read 之后不加任何参数,直接加上变数名称,那么底下就会主动出现一个空白行,等待您输入。 如果加上 -t 后面接秒数之后,例如上面的范例当中,那么 30 秒之内没有任何动作时, 该指令就会自动略过了~如果是加上 -p ,嘿嘿!后面就会有比较多可以用的提示字元给我们参考! 在指令的下达里面,比较美观啦! ^_^___FCKpd___15
- declare / typeset
declare 或 typeset 是一样的功能,就是在宣告变数的属性。如果使用 declare 后面并没有接任何参数, 那么 bash 就会主动的将所有的变数名称与内容通通叫出来,就好像使用 set 一样啦! 那么 declare 还有什么语法呢?看看先:
declare 也是个很有用的功能~尤其是当我们需要使用到底下的阵列功能时, 他也可以帮我们宣告阵列的属性喔!不过,老话一句,阵列也是在 shell script 比较常用的啦!___FCKpd___16
- 阵列属性 array 说明
某些时候,我们必须使用阵列来宣告一些变数,这有什么好处啊?在一般人的使用上, 果然是看不出来有什么好处的!不过,如果您曾经写过程式的话,那才会比较了解阵列的意义~ 阵列对写数值程式的设计师来说,可是不能错过学习的重点之一哩!好!不啰唆~ 那么要如何设定阵列的变数与内容呢?在 bash 里头,阵列的设定方式是:
- var[index]=content
比较有趣的地方在于‘读取’,一般来说,建议直接以 ${阵列} 的方式来读取, 比较正确无误的啦!___FCKpd___17
与档案系统及程序的限制关系: ulimit
想像一个状况:我的 Linux 主机里面同时登入了十个人,这十个人不知怎么搞的, 同时开启了 100 个档案,每个档案的大小约 10MBytes ,请问一下, 我的 Linux 主机的记忆体要有多大才够? 10*100*10 = 10000 MBytes ~~ 老天爷,这样,系统不挂点才有鬼哩!为了要预防这个情况的发生,所以, 我们的 bash 是可以‘限制使用者的某些系统资源’的,包括可以开启的档案数量, 可以使用的 CPU 时间,可以使用的记忆体总量等等。如何设定?用 ulimit 吧!
还记得我们在
Linux 磁碟档案系统 里面提到过,单一 filesystem 能够支援的单一档案大小与 block 的大小有关。例如 block size 为 1024 byte 时,单一档案可达 16GB 的容量。但是,我们可以用 ulimit 来限制使用者可以建立的档案大小喔! 利用 ulimit -f 就可以来设定了!例如上面的范例二,要注意单位喔!单位是 Kbytes。 若改天你一直无法建立一个大容量的档案,记得瞧一瞧 ulimit 的资讯喔!(
不过,要注意的是,一般身份使用者如果以 ulimit 设定了 -f 的档案大小, 那么他‘只能减小档案大小,不能增加档案大小喔!’)
___FCKpd___18 |
额外的变数设定功能
刚刚我们提到了两种变数取用的方法,分别是这样:
那么,在那个 ${variable} 的使用方法中,其实,我们还可以将变数进行一些修订的工作喔! 只要加上一些字符标志,后面再接着使用比对字串,就能够修改变数的内容了! 我们取底下的例子来说明:在底下的例子中,假设我的变数名称为 vbird ,且内容为 /home/vbird/testing/testing.x.sh。
这里您稍微留意一下就好了~反正就是变数后面可以接 #, ##, %, %%, /, // , 而他们存在的意义并不相同的啦~
另外,几个不同的变数内容还可以进行判断呢! 举例来说,目前我需要用到两个变数,分别是 var 与 str , 那我想要针对 str 这个变数内容是否有设定成一个字串,亦即 "expr" 来决定 var 的内容。 那我可以使用什么方法来进行判断呢?如果您会写 shell script 的话, 直接用 shell script 就好了,如果不会写,那么我们就透过简单的变数判断吧!
根据上面这张表,我们来进行几个范例的练习吧! ^_^
虽然猛一看,觉得变数没有什么奇特的地方,但是,如果仔细瞧一瞧,嘿!一堆环境变数与系统资源方面的变数, 可是会影响到我们在 bash 里头是否能够顺利作业的呢!例如 PATH 啊、ulimit 之类的~ 所以,您还是得要了解变数这个玩意才行喔! ^_^
___FCKpd___19 |
___FCKpd___20 |
另外,几个不同的变数内容还可以进行判断呢! 举例来说,目前我需要用到两个变数,分别是 var 与 str , 那我想要针对 str 这个变数内容是否有设定成一个字串,亦即 "expr" 来决定 var 的内容。 那我可以使用什么方法来进行判断呢?如果您会写 shell script 的话, 直接用 shell script 就好了,如果不会写,那么我们就透过简单的变数判断吧!
Tips: 底下的例子当中,那个 var 与 str 为变数,我们想要针对 str 是否有设定来决定 var 的值喔! 一般来说, str: 代表‘str 没设定或为空的字串时’;至于 str 则仅为‘没有该变数’。 |
变数设定方式 | str 没有设定 | str 为空字串 | str 已设定非为空字串 |
var=${str-expr} | var=expr | var= | var=$str |
var=${str:-expr} | var=expr | var=expr | var=$str |
var=${str+expr} | var=expr | var=expr | var=expr |
var=${str:+expr} | var=expr | var= | var=expr |
var=${str=expr} | str=expr var=expr | str 不变 var= | str 不变 var=$str |
var=${str:=expr} | str=expr var=expr | str=expr var=expr | str 不变 var=$str |
var=${str?expr} | expr 输出至 stderr | var= | var=str |
var=${str:?expr} | expr 输出至 stderr | expr 输出至 stderr | var=str |
根据上面这张表,我们来进行几个范例的练习吧! ^_^
___FCKpd___21 |
命令别名与历史命令:
我们知道在早期的 DOS 年代,清除萤幕上的资讯可以使用 cls 来清除,但是在 Linux 里面, 我们则是使用 clear 来清除画面的。那么可否让 cls 等于 clear 呢?可以啊!用啥方法? link file 还是什么的?别急!底下我们介绍不用 link file 的命令别名来达成。那么什么又是历史命令? 曾经做过的举动我们可以将他记录下来喔!那就是历史命令啰~底下分别来谈一谈这两个玩意儿。
命令别名设定: alias, unalias
历史命令:history
命令别名设定: alias, unalias
命令别名是一个很有趣的东西,特别是你的惯用指令特别长的时候!还有, 增设预设的属性在一些惯用的指令上面,可以预防一些不小心误杀档案的情况发生的时候! 举个例子来说,如果你要查询隐藏档,并且需要长的列出与一页一页翻看,那么需要下达‘
ls -al | more ’这个指令,我是觉得很烦啦! 要输入好几个单字!那可不可以使用 lm 来简化呢?!当然可以,你可以在命令列下面下达:
嘿嘿!我立刻多出了一个可以执行的指令喔!这个指令名称为 lm ,且其实他是执行 ls -al | more 啊!真是方便。不过, 要注意的是:‘alias 的定义规则与
变数定义规则几乎相同’, 所以你只要在 alias 后面加上你的 {
‘别名’='指令 参数' }, 以后你只要输入 lm 就相当于输入了 ls -al|more 这一串指令!很方便吧!
另外,命令别名的设定还可以取代既有的指令喔!举例来说,我们知道 root 可以移除( rm )任何资料!所以当你以 root 的身份在进行工作时,需要特别小心, 但是总有失手的时候,那么 rm 提供了一个参数来让我们确认是否要移除该档案,那就是 -i 这个参数!所以,你可以这样做:
嘿嘿!那么以后使用 rm 的时候,就不用太担心会有错误删除的情况了!这也是命令别名的优点啰! 那么如何知道目前有哪些的命令别名呢?就使用 alias 呀!
由上面的资料当中,您也会发现一件事情啊,我们在
vi 文书编辑器 里面提到 vi 与 vim 是不太一样的, vi 是比较老,而 vim 可以用来取代 vi 喔。我们的 FC4 明明就同时有 vi/vim , 为何我执行 vi 会是进入 vim 呢?呵呵!那就是因为上面的表格当中的‘ alias vi='vim' ’这个设定啦! 至于如果要取消命令别名的话,那么就使用 unalias 吧!例如要将刚刚的 lm 命令别名拿掉,就使用:
那么命令别名与变数有什么不同呢?基本上,他们的意义就不太一样了! alias 这种命令别名,你可以将他想成是建立一个新的指令名称, 至于变数则仅是将一个数值或者字串存在某个代表意义当中!举个例子好了,我们知道以前的 DOS 年代,列出目录与档案就是 dir ,而清除萤幕就是 cls ,那么如果我想要在 linux 里面也使用相同的指令呢?那就以 alias 来进行指令的别名设定:
___FCKpd___22 |
另外,命令别名的设定还可以取代既有的指令喔!举例来说,我们知道 root 可以移除( rm )任何资料!所以当你以 root 的身份在进行工作时,需要特别小心, 但是总有失手的时候,那么 rm 提供了一个参数来让我们确认是否要移除该档案,那就是 -i 这个参数!所以,你可以这样做:
___FCKpd___23 |
___FCKpd___24 |
___FCKpd___25 |
- alias cls='clear'
alias dir='ls -l' 只要加入这两行,以后你输入 cls 及 dir 就可以执行了!很方便吧!
历史命令:history
前面我们提过 bash 有提供指令历史的服务!那么如何查询我们曾经下达过的指令呢?就使用 history 啰!当然,如果觉得 histsory 要输入的字元太多太麻烦,可以使用命令别名来设定呢! 不要跟我说还不会设定呦! ^_^
在正常的情况下,当我们以 bash 登入 Linux 主机之后,系统会主动的由家目录的 ~/.bash_history 读取以前曾经下过的指令,那么 ~/.bash_history 会记录几笔资料呢?这就与你 bash 的 HISTSIZE 这个变数设定值有关了!在预设的 FC4 底下,是会记录 1000 笔资料的! 那么假设我这次登入主机后,共下达过 100 次指令,‘
等我登出时, 系统就会将 101~1100 这总共 1000 笔历史命令更新到 ~/.bash_history 当中。’ 也就是说,历史命令在我登出时,会将最近的 HISTSIZE 笔记录到我的纪录档当中啦! 当然,也可以用 history -w 强制立刻写入的!那为何用‘更新’两个字呢? 因为 ~/.bash_history 记录的笔数永远都是 HISTSIZE 那么多,旧的讯息会被主动的拿掉! 仅保留最新的!
那么 history 这个历史命令只可以让我查询命令而已吗?呵呵!当然不止啊! 我们可以利用相关的功能来帮我们执行命令呢!举例来说啰:
经过上面的介绍,了乎?历史命令用法可多了!如果我想要执行上一个指令, 除了使用上下键之外,我可以直接以‘ !! ’ 来下达上个指令的内容,此外, 我也可以直接选择下达第 n 个指令,‘ !n ’来执行,也可以使用指令标头,例如 ‘ !vi ’来执行最近指令开头是 vi 的指令列!相当的方便而好用!基本上 history 的用途很大的!但是需要小心安全的问题!尤其是 root 的历史纪录档案,这是 Cracker 的最爱!因为不小心的 root 会将很多的重要资料在执行的过程中会被纪录在 ~/.bash_history 当中,如果这个档案被解析的话,后果不堪呐!无论如何,使用 history 配合‘ ! ’曾经使用过的指令下达是很有效率的一个指令方法!
- alias h='history'
___FCKpd___26 |
那么 history 这个历史命令只可以让我查询命令而已吗?呵呵!当然不止啊! 我们可以利用相关的功能来帮我们执行命令呢!举例来说啰:
___FCKpd___27 |
Bash Shell 使用环境:
是否记得我们登入主机的时候,萤幕上头会有一些说明文字,告知我们的 Linux 版本啊什么的, 还有,登入的时候,我们还可以给予使用者一些讯息或者欢迎文字呢。此外, 我们习惯的环境变数、命令别名等等的,是否可以登入就主动的帮我设定好? 这些都是需要来注意的。另外,这些设定值又可以分为系统整体设定值与各人喜好设定值, 仅是一些档案放置的地点不同啦!这我们后面也会来谈一谈的!
绝对路径与相对路径
登录讯息显示资料: /etc/issue, /etc/motd
环境设定档: bashrc, ~/.bashrc, ~/.profile, profile...,/etc/inputrc, source
好了,我们知道在变数的设定规范当中,后输入的设定值可以取代先输入的设定值, 那么在我们登入 bash 的时候,这些设定档到底是如何读取的呢?他是这样读取的:
绝对路径与相对路径
这个议题说到快要烂掉了~从一开始到现在,这个绝对路径与相对路径的问题我们就提到不知道多少次了, 因为他实在很重要~这与 PATH 这个变数关系很大!老实说, 万一你的 PATH 没有设定完整的时候,下达指令就必须要以‘
一长列的指令连带根目录都要列出来 ’,呵呵那就是绝对路径的设定法啦! 基本上,这个‘
绝对路径’与‘
相对路径 ’的观念是很重要的!否则你将常常会找不到档案说! 所谓的‘绝对路径’就是以根目录开始写入到档案的一种命令写定方法,举例来说,我目前在 /home/test 这个 test 使用者的家目录中,我想要看看里面的 .bashrc 这个档案的资料,使用的是 more 这个指令,而这个指令在 /bin/more 当中,则正确的下达指令的方法为:
我在的目录为 /home/test !这是绝对路径写法! 而如果你还记得我们在
Linux 档案与目录管理 那一篇文章中提到的观念的话,那么应该记得使用 ls -al 时会出现两个一定存在的目录,分别是‘.’与‘..’,分别代表是‘这个路径’,与‘上一层路径’!
所以说,要执行上一层目录中的命令,可以下达‘../command ’那个 command 指的是存在的可执行档!那么我因为在 /home/test 里面,距离 /bin 有两层上层目录,所以我要使用 /bin/more 这个执行档,并且使用相对路径的方法,就必须使用:
这种相对路径的方法相当广泛的被运用于 script 当中,这是因为如前面提到的, 每个人的安装预设的目录都不相同,则使用相对路径的话, 很容易就可以找到套件之间相依软体或者是设定档案的相关性!
好了,由于系统预设并不主动搜寻目前目录下的执行档,那么你应该如何执行‘目前目录下的执行档’呢? 很简单呀!就是以相对路径的观念,由于‘ .. ’是上层,而‘ . ’是这一层,所以要执行这一层目录的命令就使用‘ ./command ’即可!例如你的 /usr/local/squid/bin 底下执行 squid 则可以写成:
请特别留意这方面的问题!‘
新手特别容易犯这个错误呢!’
___FCKpd___28 |
___FCKpd___29 |
___FCKpd___30 |
例题:关于路径搜寻的问题!为何不执行目前所在目录下的档案? 答:
|
好了,由于系统预设并不主动搜寻目前目录下的执行档,那么你应该如何执行‘目前目录下的执行档’呢? 很简单呀!就是以相对路径的观念,由于‘ .. ’是上层,而‘ . ’是这一层,所以要执行这一层目录的命令就使用‘ ./command ’即可!例如你的 /usr/local/squid/bin 底下执行 squid 则可以写成:
___FCKpd___31 |
登录讯息显示资料: /etc/issue, /etc/motd
还记得我们在终端机介面 (tty1 ~ tty6) 登入的时候,会有几行提示的字串吗? 那个字串写在哪里啊?呵呵!在 /etc/issue 里面啊!先来看看:
在 FC4 里面预设有三行,这个在我们本机登入时就会显示在 title 的地方呢~ 咦!那么那个 /r 及 /m 是啥?您可以使用 man issue 配合 man mingetty 就能够知道:
所以,如果您想要显示终端机的号码,就可以加上 /l 在 /etc/issue 档案内啰~就能够修改登入字元。 咦!但是还有个 /etc/issue.net 呢!这是啥?没啥啦!这个是提供给 telnet 这个远端登入程式用的。 当我们使用 telnet 连接到主机时,主机的登入画面就会显示 /etc/issue.net 而不是 /etc/issue 呢!
至于如果您想要让使用者登入后取得一些讯息,例如您想要让大家都知道的讯息, 那么可以将讯息加入 /etc/motd 里面去!例如:当登入后,告诉登入者, 系统将会在某个固定时间进行维护工作,可以这样做:
那么当你的使用者登入主机后,就会显示这样的讯息出来:
是否很方便啊!? ^_^
___FCKpd___32 |
issue 内的各代码意义 |
/d 本地端时间的日期; /l 显示第几个终端机介面; /m 显示硬体的等级 (i386/i486/i586/i686...); /n 显示主机的网路名称; /o 显示 domain name; /r 作业系统的版本 (相当于 uname -r) /t 显示本地端时间的时间; /s 作业系统的名称; /v 作业系统的版本。 |
所以,如果您想要显示终端机的号码,就可以加上 /l 在 /etc/issue 档案内啰~就能够修改登入字元。 咦!但是还有个 /etc/issue.net 呢!这是啥?没啥啦!这个是提供给 telnet 这个远端登入程式用的。 当我们使用 telnet 连接到主机时,主机的登入画面就会显示 /etc/issue.net 而不是 /etc/issue 呢!
至于如果您想要让使用者登入后取得一些讯息,例如您想要让大家都知道的讯息, 那么可以将讯息加入 /etc/motd 里面去!例如:当登入后,告诉登入者, 系统将会在某个固定时间进行维护工作,可以这样做:
___FCKpd___33 |
___FCKpd___34 |
环境设定档: bashrc, ~/.bashrc, ~/.profile, profile...,/etc/inputrc, source
关于取得 bash 的环境变数等资料,其实可以有系统规划与各人喜好, 一般来说,建议使用者直接修改个人设定值即可,不需要更动到系统啦~ 底下我们分别来谈一谈几个有趣的设定档喔!要注意的是,在指令列输入的变数也好、命令别名也罢, 都是针对该次登入的设定而已,所以只要您一登出,那么上次的设定值就会不见去! 因此,我们需要有几个档案来帮助我们,每次登入的时候,就已经帮我们搞定了环境的设定啰!
- 系统设定值
所谓的系统设定值,也就是说每个使用者进入到 bash shell 之后,会先读取的设定档案! 预设的设定档案有下列几个:
- /etc/sysconfig/i18n
记得我们在 几个重要变数内谈到的语系资料吗?! 那个语系是由 i18n 所维护的,而 FC4 预设的系统语系设定档就在 /etc/sysconfig/i18n 当中。 这个档案有点像这样:
我预设使用 zh_TW.UTF-8 来作为我的整体语系,当然,我可以在这里修改 LANG 以及其他相关的语系变数, 例如 LC_CTYPE 或者是 LC_TIME 等等的。不过,一般来说,使用者自己个人的设定不建议在这里做更动啦! 他们可以自行设定他们自己的设定档啊!___FCKpd___35
- /etc/profile
这个档案设定了几个重要的变数,例如:‘ PATH、USER、MAIL、 HOSTNAME、HISTSIZE、umask’等等,也同时规划出 /etc/inputrc 这个针对键盘热建设定的档案的资料内容。你可以在这里设定总体的 PATH 等等的资讯! 同时,这个档案也规划出 /etc/profile.d 及 /etc/inputrc 这两个目录与档案!
总之,你可以了解到刚刚我们学会的变数设定方式,在这个档案中也可以设定呢! 但是设定上需要特别小心,因为所有的使用者皆会使用到这个档案的资讯。通常我都喜欢将 /usr/local/bin 这个路径加成最前面,这是因为通常自己安装的套件自己最喜欢, 所以当然是最先搜寻啰! ^_^!此外,请注意一下,可以将 HISTSIZE 的大小改变一下,改成 50 就可以啦!比较安全!( 注:这个档案不论在那个 Linux distributions 当中均存在 /etc/profile 当中,所以,请特别留意此一档案即可! )。
- /etc/bashrc
这个档案在规划 umask 的功能,也同时规划出提示字元的内容 (就是里头那个 PS1 啦!) 。特别留意的是,这个档案在不同的 Linux distribution 里面,摆放的位置可能不太一样呢! 所以需要查询一下才行呦!
- /etc/profile.d/*.sh
/etc/profile.d 是一个目录,里面针对 bash 及 C-shell 规范了一些资料。 以 FC4 为例,这个目录里面就针对了颜色、语系、vim 及 which 等指令进行一些额外的设定, 例如 alias 之类的规范值。我们的 vim 被用 alias 命名为 vi 就是在这个目录下被设定好的。 当然啦,这个目录的由来其实是在 /etc/profile 这个档案内规范的啦! 你可以自行设定一些 *.sh 的档名的档案来书写自己的系统设定值喔!
- /etc/man.config
这个档案乍看之下好像跟 bash shell 没相关性,但是对于系统管理员来说, 却也是很重要的一个档案!这的档案的内容‘ 规范了使用 man 的时候, man page 的路径到哪里去寻找!’所以说的简单一点,这个档案规定了下达 man 的时候,该去哪里查看资料的路径设定!那么什么时候要来修改这个档案呢?如果你是以 tarball 的方式来安装你的资料,那么你的 man page(指令说明档案)可能会放置在 /usr/local/softpackage/man 里头,那个 softpackage 是你的套件名称, 这个时候你就得以手动的方式将该路径加到 /etc/man.config 里头,否则使用 man 的时候就会找不到相关的说明档啰。这就是系统在设定的时候常常会使用的档案!需要特别留意的是,通常设定完了这几个档案之后,都需要先 logout 在 login 之后才会将设定整个启动起来!
事实上,这个档案内最重要的其实是 MANPATH 这个变数设定啦! 我们搜寻 man page 时,会依据 MANPATH 的路径去分别搜寻啊!另外,要注意的是, 这个档案在各大不同版本 Linux distributions 中,档名都不太相同,例如 FC4 用的是 /etc/man.config ,而 SuSE 用的则是 /etc/manpath.config , 可以利用 [tab] 按键来进行档名的补齐啦!
- 个人设定值
那么个人的喜好设定在哪里?嘿嘿嘿嘿!那就是在个人家目录的几个隐藏档当中啰! 分别会使用到底下的几个档案啦!( 注意!底下的档案都是隐藏档,需要使用 ls -al 方能显示出来 ) ,另外,注意一下啰!底下那个‘ ~ ’代表的是‘家目录’的意思:
- ~/.bash_profile, ~/.bash_login, ~/.profile
这三个档案通常只要一个就够了,一般预设是以 ~/.bash_profile 的档名存在。 会有这么多的档案,其实是因应其他 shell 转换过来的使用者的习惯而已。 这个档案可以定义个人化的路径 (PATH) 与环境变数等等。不过,还是有顺位上的差异, bash 启动时, 会先去读取 ~/.bash_profile,找不到时,就去读取 ~/.bash_login ,然后才是 ~/.profile。
- ~/.bashrc
鸟哥一般都是将自己的需要输入在这个档案里面的呢! 我的个人化设定值都会写在这里说~例如命令别名、路径等等。 这个档案在您每次执行 shell script 的时候都会被重新使用一遍,所以是最完整的。 而上头的 ~/.bash_profile 则只有在登入的时候会被读取一次。
- ~/.bash_history
还记得我们在历史命令提到过这个档案吧?!呵呵!没错~预设的情况下, 我们的历史命令就记录在这里啊!而这个档案能够记录几笔资料,则与 HISTSIZE 这个变数有关啊。每次登入 bash 后,bash 会先读取这个档案,将所有的历史指令读入记忆体, 因此,当我们登入 bash 后就可以查知上次使用过哪些指令啰。至于更多的历史指令, 请自行回去参考喔!
- ~/.bash_logout
这个档案则记录了‘当我登出 bash 后,系统再帮我做完什么动作后才离开’的意思。 你可以去读取一下这个档案的内容,预设的情况下,登出时, bash 只是帮我们清掉萤幕的讯息而已。 不过,你也可以将一些备份或者是其他你认为重要的工作写在这个档案中(例如清空暂存档), 那么当你离开 Linux 的时候,就可以解决一些烦人的事情啰!
-
- 先读取 /etc/profile ,再根据 /etc/profile 的内容去读取其他额外的设定档, 例如 /etc/profile.d 与 /etc/inputrc 等等设定档;
- 根据不同的使用者,到使用者家目录去读取 ~/.bash_profile 或 ~/.bash_login 或 ~/.profile 等设定档;
- 根据不同使用者,到他家目录去读取 ~/.bashrc 。
仔细看到上头这个档案,会不会觉得奇怪啊!为什么会有第五行的‘ . /etc/bashrc ’呢? 那个小数点 (.) 代表什么意思啊??其实 if [ ... ]; then .... fi 是 shell script 当中的程式写法, 这个我们会在下一章当中介绍。不过,那个 . 则需要好好的谈一谈喔!一般来说,如果修改完了设定档, 通常就是 logout 后再重新 login 到 bash 内,就能够将环境设定档重读了!不过, 我们可以使用底下的方式来让该设定档立即生效:___FCKpd___36
利用 source 或小数点 (.) 都可以将设定档的内容读进来目前的 shell 环境中! 举例来说,我修改了 ~/.bashrc ,那么不需要登出,立即以 source ~/.bashrc 就可以将刚刚最新设定的内容读进来目前的环境中!很不错吧!此外,什么时候会使用到不同的设定档呢? 最常发生在一个人的工作环境分为多重的时候了!举个例子来说,在我的大型主机中, 我常常需要负责两到三个不同的案子,每个案子所需要处理的环境变数订定并不相同, 那么我就将这两三个案子分别编写属于该案子的环境变数设定档案,当我需要该环境时,就直接‘ source 变数档 ’,如此一来,环境变数的设定就变的更简便而灵活了!___FCKpd___37
- login shell 与 non-login shell
事实上,这些环境设定档在读取时,还是有一些差异的,这就得要谈到所谓的‘login shell’与 ‘non-login shell’的差异了。基本上,就字面上的意义来解释的话, 所谓的 loign shell 指的就是当使用者登入 Linux 系统时,所取得的那个 shell 称为 login shell。 当登入后,再去执行其他的 shell 时,其他的 shell 就是 non-login shell 了。举例来说,我以 dmtsai 这个使用者身份登入 Linux 后,然后为了要执行一些数值模拟的工作,而去执行 csh 这个 C shell , 那么此时我就取得了 non-login shell 了。
另外一个例子是,当我以 X Window 的环境登入 Linux 时,我们不是可以使用‘终端机’来开启 shell 吗?当登入 Linux 的时候所取得的那个 X 的环境也可以读入 login shell 的。因此,在 X 环境下所启动的终端机,那些 shell 都是 non-login shell 喔!
login 与 non-login shell 的差异除了取得的时机不同之外,其实他们读取的环境设定档也不相同。 我们上头说过一些个人的环境设定档案了吧?那么这两种类型的 shell 该读取什么档案呢? 当登入 Linux ,亦即是取得 login shell 时,会读取 ~/.bash_profile, ~/.bash_login, ~/.profile, 这三个档案的优先顺序已经在上面提过,自行参考一下。至于在取得 login shell 后继续动作的其他 non-login shell ,读取的就是仅有 ~/.bashrc 啰~。而大部分的 linux distributions 都会将 ~/.bash_profile 的内容指到 ~/.bashrc 去,这样比较简单啰~
终端机的环境设定: 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 来达成的。 几个重要的代表意义是:___FCKpd___38
- eof : End of file 的意思,代表‘结束输入’。
- erase : 向后删除字元,
- intr : 送出一个 interrupt (中断) 的讯号给目前正在 run 的程序;
- kill : 删除在目前指令列上的所有文字;
- quit : 送出一个 quit 的讯号给目前正在 run 的程序;
- start : 在某个程序停止后,重新启动他的 output
- stop : 停止目前萤幕的输出;
- susp : 送出一个 terminal stop 的讯号给正在 run 的程序。
那么从此之后,你的删除字元就得要使用 [ctrl]+h 啰,按下 [backspace] 则会出现 ^? 字样呢! 如果想要回复利用 [backspace] ,就下达 stty erase ^? 即可啊! 至于更多的 stty 说明,记得参考一下 man stty 的内容喔!___FCKpd___39
除了 stty 之外,其实我们的 bash 还有自己的一些终端机设定值呢!那就是利用 set 来设定的! 我们之前提到一些变数时,可以利用 set 来显示,除此之外,其实 set 还可以帮我们设定整个指令输出/输入的环境。 例如记录历史命令、显示错误内容等等。
另外,其实我们还有其他的按键设定功能呢!就是在 /etc/inputrc 这个档案里面设定。___FCKpd___40
还有例如 /etc/DIR_COLORS* 与 /etc/termcap 等,也都是与终端机有关的环境设定档案呢! 不过,事实上,鸟哥并不建议您修改 tty 的环境呢,这是因为 bash 的环境已经设定的很亲和了, 我们不需要额外的设定或者修改,否则反而会产生一些困扰。不过,写在这里的资料, 只是希望大家能够清楚的知道我们的终端机是如何进行设定的喔! ^_^___FCKpd___41
万用字元与特殊符号:
嘿嘿!在 bash 里头还支援一些万用字元喔 (wild card) !多了这些万用字元, 我们利用 bash 处理资料就更方便了!底下我们列出一些常用的万用字元喔:
符号 内容 * 万用字元,代表 0 个或多个字元(或数字) ? 万用字元,代表‘一定有’一个字母 # 注解,这个最常被使用在 script 当中,视为说明! / 跳脱符号,将‘特殊字元或万用字元’还原成一般字元 | 分隔两个管线命令的界定; ; 连续性命令的界定(注意!与管线命令并不相同) ~ 使用者的家目录 $ 亦即是变数之前需要加的变数取代值 & 将指令变成背景下工作 ! 逻辑运算意义上的‘非’ not 的意思! / 路径分隔的符号 >, >> 输出导向,分别是‘取代’与‘累加’ ' 单引号,不具有变数置换的功能 " 具有变数置换的功能! ` ` 两个‘ ` ’中间为可以先执行的指令! ( ) 在中间为子 shell 的起始与结束 [ ] 在中间为字元的组合 { } 在中间为命令区块的组合! 组合按键 执行结果 Ctrl + C 终止目前的命令 Ctrl + D 输入结束(EOF),例如邮件结束的时候; Ctrl + M 就是 Enter 啦! Ctrl + S 暂停萤幕的输出 Ctrl + Q 恢复萤幕的输出 Ctrl + U 在提示字元下,将整列命令删除 Ctrl + Z ‘暂停’目前的命令
在上面的‘按键组合’当中,有没有发现跟上个小节很相似的内容啊!? 呵呵~没错啦!那些组合键都可以在 stty 当中来进行不同的设定的!好玩吧! 至于上面的万用字元当中,最常用的就属 *, ?, [] 及 ` 了!我们提几个简单的例子:
上面几个例子相当的有趣!尤其是最后面两个!需要注意的是, [1-5] 里面‘代表只有一个字元’但是范围可以由 1-5 ,这样来说的话,那么我们如果允许‘只要档名里面含有至少一个大写字元’时,就可以将档案 copy 出来的话,可以这样做:___FCKpd___42
- cp *[A-Z]* /tmp
- ls -lda /etc/*[0-9]*
- ls -lda /etc/*[35]*
- ls -lda /etc/[!a-z]*
- 系统先执行 uname -r 找出输出的结果;
- 将结果累加在目录上面,来执行 cd 的功能!
- cd /lib/modules/$(uname -r)/kernel
资料流重导向
资料流重导向 (redirect) 由字面上的意思来看,好像就是将‘资料给他传导到其他地方去’的样子? 呵呵!是啊是啊!没错~资料流重导向就是将某个指令执行后应该要出现在萤幕上的资料, 给他传输到其他的地方,例如档案或者是装置 (例如印表机之类的!)!这玩意儿在 Linux 的文字模式底下可重要的! 尤其是如果我们想要将某些资料储存下来时,就更有用了!
什么是资料流重导向
好家伙!什么是资料流重导向啊?这得要由指令的执行结果谈起! 一般来说,如果你要执行一个指令,通常他会是这样的:
图三、指令执行过程的资料传输情况
我们执行一个指令的时候,这个指令可能会由档案读入资料,经过处理之后,再将资料输出到萤幕上。 在图三当中, standard output 与 standard error 分别代表标准输出与标准错误输出, 这两个玩意儿预设都是输出到萤幕上面来的啊!举个简单例子来说, 我们下达‘ cat /etc/crontab /etc/vbirdsay ’这个指令时,cat 会由 /etc/crontab 与 /etc/vbirdsay 读入资料, 然后再将资料输出到萤幕上,不过,因为系统本来就不存在 /etc/vbirdsay 这个档案, 所以就会显示错误讯息,这个错误讯息也会输出到萤幕上来喔!
在这样的过程当中,我们可以将 standard error (简称 stderr) 与 standard output (简称 stdout) 给他传送到其他不同的地方,而不是萤幕上头!传送的目标处,通常是档案或者是装置! 而传送的指令则是如下所示:-
- 标准输入(stdin) :代码为 0 ,使用 < 或 << ;
- 标准输出(stdout):代码为 1 ,使用 > 或 >> ;
- 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;
此时,原本应该在萤幕上面出现的资料通通不见去~因为那些资料都被写入到 ~/rootfile 去了! 当然,那个档案的档名随便你取啦~如果你下达:‘ cat ~/rootfile ’就可以看到原本应该在萤幕上面的资料啰。 那么如果我再次下达:‘ ls -l /home > ~/rootfile ’后,那么那个 ~/rootfile 档案的内容变成什么? 呵呵!变成‘仅有 ls -l /home 的资料’而已!咦!原本的 ls -l / 资料就不见了吗?是的! 因为该档案的建立方式是:___FCKpd___43
-
- 该档案 (本例中是 ~/rootfile) 若不存在,系统会自动的将他建立起来,但是,
- 当这个档案存在的时候,那么系统就会先将这个档案内容清空,然后再将资料写入!
- 也就是若以 > 输出到一个既存档案中,呵呵,那个档案就会被覆盖掉啰!
command >
1>
2>
2>>
<装置或档案
当然啦,一串指令的最左边一定是指令,而在 >,2>,< 右边的,必须是档案或装置才行! 此外,那个 > 会等于 1> ,因为 standard output 代码是 1 ,可以省略啦! 再者, 1 与 > 之间并没有空格喔!是紧接在一起的!注意注意!我们底下来玩几个东西好了:
好了,对于‘ > , >> ’这两个东西有一定的概念之后,我们来深入的谈一谈‘资料流重导向’的观念吧! 如前所述,基本上, Linux 执行的结果中,可以约略的分成‘正确输出’与‘错误输出’两种资料。 例如,当你以一般身份执行 find 这个指令时,例如执行‘ find / -name testing ’时,由于你是一般身份,又有些资料夹是不允许一般身份者进入的, 所以啰,当你使用 find 时,就会有错误讯息发生了!但同时如果有 testing 这个档案在你可以进入的资料夹当中,那么萤幕也会输出到给你看!因此, 就具有正确的与错误的输出两种啰!(分别称为 Stdout 与 Stderror)例如下面为执行结果: 里面的‘ find: /home/root: Permission denied ’就告诉你该资料夹你没有权限进入, 这就是错误的输出了,那么‘ /home/dmtsai/tseting ’就是正确的输出了!___FCKpd___44
好了,那么假如我们想要将资料输出到 list 这个档案中呢?执行‘ find / -name testing > list ’ 会有什么结果?呵呵,你会发现 list 里面存了刚刚那个‘正确’的输出资料, 至于萤幕上还是会有错误的讯息出现呢!伤脑筋!如果想要将正确的与错误的资料分别存入不同的档案中需要怎么做?! 呵呵!其实在资料的重导向方面,正确的写法应该是‘ 1> ’与‘ 2> ’才对!但是如果只有 > 则预设是以 1> 来进行资料的!那个 1> 是输出正确资料, 2> 则是错误资料输出项目。也就是说:___FCKpd___45
-
- 1> :是将正确的资料输出到指定的地方去
- 2> :是将错误的资料输出到指定的地方去
这样一来,刚刚执行的结果中,有 Permission 的那几行错误资讯都会跑到 list_error 这个档案中,至于正确的输出资料则会存到 list_right 这个档案中啰!这样可以了解了吗? 如果有点混乱的话,去休息一下再来看看吧!!___FCKpd___46
再来,如果我只要正确的资料,错误的资讯我不要了呢?呵呵,这个时候 /dev/null 这个垃圾桶就很重要了!/dev/null 是什么呢? 基本上,那就有点像是一个‘黑洞’的垃圾桶功能!当你输入的任何东西导向到这个虚拟的垃圾桶装置时, ‘他就会凭空消失不见了~~’,这个东西有用的很!例如上面的例子中,我们可以这么做,来将错误的资讯丢掉!
很神奇呦! error message 就会‘不见了!’呵呵!真高兴!另外, 如果我要将资料都写到同一个档案中呢?这个时候写法需要用到特殊写法,请注意底下的写法呦!___FCKpd___47
请特别留意这一点呢!同时写入同一个档案需要使用 2>&1 才对呦!___FCKpd___48
OK!了解了 >, 2>, >> 与 /dev/null 之后,那么那个 < 又是什么呀!?呵呵!以最简单的说法来说, 那就是‘将原本需要由键盘输入的资料,经由档案来读入’的意思。 举例来说,我们可以使用 cat 在键盘上面输入一些资料,然后写入一个档案内,例如:
此时就会有 catfile 这个档案产生,而且该档案的内容就是刚刚输入的内容喔。 那么,我是否可以使用其他档案来取代键盘输入呢?可以啊!这样做!___FCKpd___49
我可以先编辑 somefile ,然后再以上述的指令来将资料输出到 catfile 去呢!这样可以理解了吗? 能够理解 < 之后,再来则是怪可怕一把的 << 这个连续两个小于的符号了~ 他代表的是‘结束的输入字元’的意思!举例来讲:‘我要用 cat 直接将输入的讯息输出到 catfile 中, 且当输入 eof 时,该次输入就结束’,那我可以这样做:___FCKpd___50
看到了吗?利用 << 右侧的控制字元,我们可以终止一次输入, 而不必输入 [crtl]+d 来结束哩!这对程式写作很有帮助喔!好了,那么为何要使用命令输出重导向呢? 这个问题一定会困扰你一下下的,如果你从来都没有写过 script 的话!好了,我们来说一说吧!___FCKpd___51
-
- 当萤幕输出的资讯很重要,而且我们需要将他存下来的时候;
- 背景执行中的程式,不希望他干扰萤幕正常的输出结果时;
- 一些系统的例行命令(例如写在 /etc/crontab 中的档案)的执行结果,希望他可以存下来时;
- 一些执行命令,我们已经知道他可能的错误讯息,所以想以‘ 2> /dev/null ’将他丢掉时;
- 错误讯息与正确讯息需要分别输出时。
命令执行的判断依据: ; , &&, ||
在某些时候,我们希望可以一次执行多个指令,例如关机时,希望我可以先执行两次 sync ,然后才 shutdown 电脑,那么可以怎么作呢?这样做呀:
在指令与指令中间利用分号 (;) 来隔开,这样一来,分号前的指令执行完后, 就会立刻接着执行后面的指令了。这真是方便啊~再来,换个角度来想, 万一我想要在某个目录底下建立一个档案,也就是说,如果该档案存在的话, 那我才建立这个档案,如果不存在,那就算了~目录是否存在可以使用一些 bash 提供的判断式功能, 但这里假设我不晓得那个指令,但我知道我可以使用 ls 来判断是否有该目录的存在, 也就是说,我可以利用 ls directoryname 判断是否存在,然后以 touch 建立一个档案, 这两个指令有相关性,那该如何写呢?呵呵!可以利用 && 来作喔!___FCKpd___52
是否记得我们在变数的章节里面谈过这个奇怪的变数‘ $? ’呢? 如果指令执行结果没有错误讯息,那就会回传 $?=0 ,如果有错误, 那回传值就不会是 0 啊!经由这样的判断,我们也可以利用 && 来决定, 当前面的指令执行结果为正确 (例如:仅有 standard output 时),就可以接着执行后续的指令, 否则就予以略过!因此,当 ls /tmp 没有问题,那么就会接着执行 touch /tmp/testingagin 了! 万一是这样:___FCKpd___53
因为我的系统里面根本就不可能存在 /vbird 这个目录呢!所以,执行 ls /vbird 就会回传错误, 那么后续的 touch /vbird/test 自然就不会动作啰!了解吗?___FCKpd___54
再换个角度来想,如果我想要当某个档案不存在时,就去建立那个档案, 否则就略过呢?很简单啊~可以这样做:
那个 || 刚好完全跟 && 相反,当前一个指令有错误时,在 || 后面的指令才会被执行! ( 要注意,那个 | 是两个 | ,而 | 按键则是反斜线 / 同一个按键, 因此,按下 [Shift] 加上 [/] 就会出现那个 | 啰!) 因此,简单的来说,当 ls /tmp/vbirding 发生错误时,才会使用 touch /tmp/vbirding 去建立这个档案的意思。 是否很有趣啊?这个 || 及 && 对于系统管理员在管理某些档案权限、存在等问题时, 可是很有用的东西喔!好了,现在我们来玩比较难一点的,看看底下的例题:___FCKpd___55
例题:以 ls 测试 /tmp/vbirding 是否存在,若存在则显示 "exist" ,若不存在,则显示 "not exist"!
答:-
这又牵涉到逻辑判断的问题,如果存在就显示某个资料,若不存在就显示其他资料,那我可以这样做:
ls /tmp/vbirding && echo "exist" || echo "not exist"
意思是说,当 ls /tmp/vbirding 执行后,若正确,就执行 echo "exist" ,若有问题,就执行 echo "not exist" !那如果我写成:
ls /tmp/vbirding || echo "not exist" && echo "exist"
对不对啊?这其实是有问题的,为什么呢?因为指令是一个一个往下执行,因此,在上面的例子当中,如果 /tmp/vbirding 不存在时,他会:
- 若 ls /tmp/vbirding 不存在,因此回传一个非为 0 的数值;
- 接下来经过 || 的判断,发现前一个指令回传非为 0 的数值,因此,程式开始执行 echo "not exist" ,而 echo "not exist" 程式肯定可以执行成功,因此会回传一个 0 值给后面的指令;
- 经过 && 的判断,咦!是 0 啊!所以就开始执行 echo "exist" 。
所以啊,嘿嘿!第二个例子里面竟然会同时出现 not exist 与 exist 呢!真神奇~
经过这个范例的练习,您应该会了解,由于指令是一个接着一个去执行的,因此,如果真要使用判断, 那么这个 && 与 || 的顺序就不能搞错~一般来说,判断式最多会有三个,也就是:- command1 && command2 || command3
管线命令 (pipe)
就如同前面所说的, bash 命令执行的时候有输出的资料会出现! 那么如果这群资料必需要经过几道手续之后才能得到我们所想要的格式,应该如何来设定? 这就牵涉到管线命令的问题了 (pipe) , 管线命令使用的是‘ | ’这个界定符号! 另外, 管线命令与‘连续下达命令’是不一样的呦! 这点底下我们会再说明。底下我们先举一个例子来说明一下简单的管线命令。
假设我们想要知道 /etc/ 底下有多少档案,那么可以利用 ls /etc 来查阅,不过, 因为 /etc 底下的档案太多,导致一口气就将萤幕塞满了~不知道前面输出的内容是啥?此时,我们可以透过 less 指令的协助,利用:
嘿嘿!如此一来,使用 ls 指令输出后的内容,就能够被 less 读取, 并且利用 less 的功能,我们就能够前后翻动相关的资讯了!很方便是吧?呵呵! 我们就来了解一下这个管线命令‘ | ’的用途吧!___FCKpd___56
这个管线命令‘ | ’仅能处理经由前面一个指令传来的正确资讯,也就是 standard output ( STDOUT ) 的资讯,对于 stdandard error 并没有直接处理的能力,请记得。那么整体的管线命令可以使用下图表示之:
图四、管线命令的处理示意图
在每个管线的前后部分都是‘指令’呢!而后一个指令的输入乃是由前一个指令的输出而来的! 不过,要注意的是,在 Linux 的环境中,很多的讯息处理都是以‘行’为单位~ 也就是以是否具有 [Enter] 标志 (CR) 来作为一段处理的依据喔! 底下我们来谈一谈一些基本的管线命令指令介绍:
撷取命令: cut, grep
什么是撷取命令啊?说穿了,就是将一段资料经过分析后,取出我们所想要的。 或者是,经由分析关键字,取得我们所想要的那一行! 不过,要注意的是,一般来说,撷取讯息通常是针对‘一行一行’来分析的, 并不是整篇讯息分析的喔~底下我们介绍两个很常用的讯息撷取命令:
- cut
cut 不就是‘切’吗?没错啦!这个指令可以将一段讯息的某一段给他‘切’出来~ 处理的讯息是以‘行’为单位喔!底下我们就来谈一谈:
这个 cut 实在很好用!不过,说真的,除非你常常在分析 log 档案,否则使用到 cut 的机会并不多!好了! cut 主要的用途在于将‘同一行里面的资料进行分解!’, 最常使用在分析一些数据或文字资料的时候!这是因为有时候我们会以某些字元当作分割的参数, 然后来将资料加以切割,以取得我们所需要的资料。我也很常使用这个功能呢!尤其是在分析 log 档案的时候!不过, cut 在处理多空格相连的资料时,可能会比较吃力一点~___FCKpd___57
- grep
刚刚的 cut 是将一行讯息当中,取出某部分我们想要的,而 grep 则是分析一行讯息, 若当中有我们所需要的资讯,就将该行拿出来~简单的语法是这样的:
grep 是个很棒的指令喔!他支援的语法实在是太多了~用在正规表示法里头, 能够处理的资料实在是多的很~不过,我们这里先不谈正规表示法~下一章再来说明~ 您先了解一下, grep 可以解析一行文字,取得关键字,若该行有存在关键字, 就会整行列出来!___FCKpd___58
排序命令: sort, wc, uniq
很多时候,我们都会去计算一次资料里头的相同型态的资料总数,举例来说, 使用 last 可以查得这个月份有登入主机者的身份。那么我可以针对每个使用者查出他们的总登入次数吗? 此时就得要排序与计算之类的指令来辅助了!底下我们介绍几个好用的排序与统计指令喔!
- sort
sort 是很有趣的指令,他可以帮我们进行排序,而且可以依据不同的资料型态来排序喔! 例如数字与文字的排序就不一样。此外,排序的字元与语系的编码有关,因此, 如果您需要排序时,建议使用 LC_ALL=C 来让语系统一,资料排序比较好一些。
sort 同样是很常用的指令呢!因为我们常常需要比较一些资讯啦! 举个上面的第二个例子来说好了!今天假设你有很多的帐号,而且你想要知道最大的使用者 ID 目前到哪一号了!呵呵!使用 sort 一下子就可以知道答案咯!当然其使用还不止此啦! 有空的话不妨玩一玩!___FCKpd___59
- uniq
如果我排序完成了,想要将重复的资料仅列出一个显示,可以怎么做呢?
这个指令用来将‘重复的行删除掉只显示一个’,举个例子来说, 你要知道这个月份登入你主机的使用者有谁,而不在乎他的登入次数,那么就使用上面的范例, (1)先将所有的资料列出;(2)再将人名独立出来;(3)经过排序;(4)只显示一个! 由于这个指令是在将重复的东西减少,所以当然需要‘配合排序过的档案’来处理啰!___FCKpd___60
- wc
如果我想要知道 /etc/man.config 这个档案里面有多少字?多少行?多少字元的话, 可以怎么做呢?其实可以利用 wc 这个指令来达成喔!他可以帮我们计算输出的讯息的整体资料!
wc 也可以当作指令?呵呵!这可不是上洗手间的 WC 呢! 这是相当有用的计算档案内容的一个工具组喔!举个例子来说, 当你要知道目前你的帐号档案中有多少个帐号时,就使用这个方法:‘ cat /etc/passwd | wc -l ’啦!因为 /etc/passwd 里头一行代表一个使用者呀! 所以知道行数就晓得有多少的帐号在里头了!而如果要计算一个档案里头有多少个字元时,呵呵!就使用 wc -w 这个参数吧!___FCKpd___61
双向重导向: tee
想个简单的东西,我们由前一节知道 > 会将资料流整个传送给档案或装置, 因此我们除非去读取该档案或装置,否则就无法继续利用这个资料流。 万一我想要将这个资料流的处理过程中,将某段讯息存下来,应该怎么做?呵呵! 利用 tee 就可以啰~我们可以这样简单的看一下:
图五、tee 的工作流程
同时将资料流分送到档案去与萤幕 (screen);而输出到萤幕的,其实就是 stdout ,可以让下个指令继续处理喔!
有没有发现在命令重导向的时候,如果我们要将资料送出到档案的时候, 萤幕上就不会出现任何的资料!那么如果我们需要将资料同时显示在萤幕上跟档案中呢?呵呵!这个时候就需要 tee 这个指令啰!使用 last 可以查看到这个月份的登入资料,而使用了 tee 之后,会将资料同时传给下一个命令去执行,也会将资料写入 last.list 这个档案中!也是个好帮手!___FCKpd___62
字元转换命令: tr, col, join, paste, expand
我们在 vi 文书处理器 章节当中,提到过 DOS 断行字元与 Unix 断行字元的不同, 并且可以使用 dos2unix 与 unix2dos 来完成转换。好了,那么思考一下,是否还有其他常用的字元替代? 举例来说,要将大写改成小写,或者是 [tab] 按键转成空白键?还有,如何将两篇讯息整合成一篇? 底下我们就来介绍一下这些字元转换命令在管线当中的使用方法:
- tr
tr 可以用来删除一段讯息当中的文字,或者是进行文字讯息的替换!
其实这个指令也可以写在‘正规表示法’里头!因为他也是由正规表示法的方式来取代资料的! 以上面的例子来说,使用 [] 可以设定一串字呢! 也常常用来取代档案中的怪异符号! 例如上面第三个例子当中,可以去除 DOS 档案留下来的 ^M 这个断行的符号!这东西相当的有用!相信处理 Linux & Windows 系统中的人们最麻烦的一件事就是这个事情啦!亦即是 DOS 底下会自动的在每行行尾加入 ^M 这个断行符号!这个时候我们可以使用这个 tr 来将 ^M 去除! ^M 可以使用 /r 来代替之!___FCKpd___63
- col
虽然 col 有他特殊的用途,不过,很多时候,他可以用来简单的处理将 [tab] 按键取代成为空白键! 例如上面的例子当中,如果使用 cat -A 则 [tab] 会以 ^I 来表示。 但经过 col -x 的处理,则会将 [tab] 取代成为对等的空白键!___FCKpd___64
- join
join 看字面上的意义 (加入/参加) 就可以知道,他是在处理两个档案之间的资料, 而且,主要是在处理‘ 两个档案当中,有 "相同资料" 的那一行,将他加在一起’的意思。我们利用底下的简单例子来说明:
这个 join 在处理两个相关的资料档案时,就真的是很有帮助的啦! 例如上面的案例当中,我的 /etc/passwd, /etc/shadow, /etc/group 都是有相关性的, 其中 /etc/passwd, /etc/shadow 以帐号为相关性,至于 /etc/passwd, /etc/group 则以所谓的 GID (帐号的数字定义) 来作为他的相关性。根据这个相关性, 我们可以将有关系的资料放置在一起!这在处理资料可是相当有帮助的! 但是上面的例子有点难,希望您可以静下心好好的看一看原因喔!___FCKpd___65
- paste
这个 paste 就要比 join 简单多了!相对于 join 必须要比对两个档案的资料相关性, paste 就直接‘将两行贴在一起,且中间以 [tab] 键隔开’而已!简单的使用方法:
___FCKpd___66
- expand
这玩意儿就是在将 [tab] 按键转成空白键啦~可以这样玩:
expand 也是挺好玩的~他会自动将 [tab] 转成空白键~所以,以上面的例子来说, 使用 cat -A 就会查不到 ^I 的字符啰~此外,因为 [tab] 最大的功能就是格式排列整齐! 我们转成空白键后,这个空白键也会依据我们自己的定义来增加大小~ 所以,并不是一个 ^I 就会换成 8 个空白喔!这个地方要特别注意的哩! 此外,您也可以参考一下 unexpand 这个将空白转成 [tab] 的指令功能啊! ^_^___FCKpd___67
分割命令: split
如果你有档案太大,导致一些携带式装置无法复制的问题,嘿嘿!找 split 就对了! 他可以帮你将一个大档案,依据档案大小或行数来分割,就可以将大档案分割成为小档案了! 快速又有效啊!真不错~
在 Windows 的情况下,你要将档案分割需要如何作?!伤脑筋吧!呵呵!在 Linux 底下就简单的多了!你要将档案分割的话,那么就使用 -b size 来将一个分割的档案限制其大小,如果是行数的话,那么就使用 -l line 来分割!好用的很!如此一来,你就可以轻易的将你的档案分割成 floppy 的大小,方便你 copy 啰!___FCKpd___68
参数代换: xargs
xargs 是在做什么的呢?就以字面上的意义来看, x 是加减乘除的乘号,args 则是 arguments (参数) 的意思,所以说, 这个玩意儿就是在产生某个指令的参数的意思! xargs 可以读入 stdin 的资料,并且以空白字元或断行字元作为分辨,将 stdin 的资料分隔成为 arguments 。 因为是以空白字元作为分隔,所以,如果有一些档名或者是其他意义的名词内含有空白字元的时候, xargs 可能就会误判了~他的用法其实也还满简单的!就来看一看先!
其实,在 man xargs 里面就有三四个小范例,您可以自行参考一下内容。 此外, xargs 真的是很好用的一个玩意儿!您真的需要好好的参详参详!___FCKpd___69
关于减号 - 的用途
管线命令在 bash 的连续的处理程序中是相当重要的!另外,在 log file 的分析当中也是相当重要的一环, 所以请特别留意!另外,在管线命令当中,常常会使用到前一个指令的 stdout 作为这次的 stdin , 某些指令需要用到档案名称 (例如 tar) 来进行处理时,该 stdin 与 stdout 可以利用减号 "-" 来替代, 举例来说:
上面这个例子是说:‘我将 /home 里面的档案给他打包,但打包的资料不是纪录到档案,而是传送到 stdout; 经过管线后,将 tar -cvf - /home 传送给后面的 tar -xvf - ’。后面的这个 - 则是取用前一个指令的 stdout, 因此,我们就不需要使用 file 了!这是很常见的例子喔!注意注意!___FCKpd___70
本章习题练习
( 要看答案请将滑鼠移动到‘答:’底下的空白处,按下左键圈选空白处即可察看 )- 如何显示 HOME 这个环境变数?
echo $HOME
- 如何得知目前的所有变数与环境变数的设定值?
环境变数用 env 而所有变数用 set 即可显示
- 我是否可以设定一个变数名称为 3myhome ?
不行!变数不能以数字做为开头,参考变数设定规则的内容
- 如何取消变数与命令别名的内容?
使用 unset 及 unalias 即可
- 如何设定一个变数名称为 name 内容为 It’s my name ?
name=It/’s/ my/ name 或 name=”It’s my name
- 环境变数档案的载入顺序?
先由 /etc/passwd 取得 bash 这个 shell ,再到 /etc/profile 读取主要的环境变数,同时亦会将 /etc/inputrc 及 /etc/profile.d 内容均读入。之后,再到个人的家目录读取 ~/.bash_profile 及 ~/.bashrc 等档案!
- man page 的路径设定档案?
/etc/man.config 或 /etc/man.conf
- 试说明 ‘, “, 与 ` 这些符号在变数定义中的用途?
参考变数规则那一章节,其中, “ 可以具有变数的内容属性, ‘ 则仅有一般字元,至于 ` 之内则是可先被执行的指令。
- 跳脱符号 / 有什么用途?
可以用来跳脱特殊字元,例如 Enter, $ 等等,使成为一般字元!
- 连续命令中, ;, &&, || 有何不同?
分号可以让两个 command 连续运作,不考虑 command1 的输出状态, && 则前一个指令必需要没有错误讯息,亦即回传值需为 0 则 command2 才会被执行, || 则与 && 相反!
- 如何将 last 的结果中,独立出帐号,并且印出本月份曾经登入过的帐号?
last | cut -d “ “ -f1 | sort | uniq
- 请问 foo1 && foo2 | foo3 > foo4 ,这个指令串当中, foo1/foo2/foo3/foo4 是指令还是档案? 整串指令的意义为?
foo1/foo2 与 foo3 都是指令, foo4 是装置或档案。整串指令意义为:
- 当 foo1 执行结果有错误时,则该指令串结束;
- 若 foo1 执行结果没有错误时,则执行 foo2 | foo3 > foo4 ;
- foo2 将 stdout 输出的结果传给 foo3 处理;
- foo3 将来自 foo2 的 stdout 当成 stdin ,处理完后将资料流重新导向 foo4 这个装置/档案
- 如何秀出在 /bin 底下任何以 a 为开头的档案档名的详细资料?
ls -l /bin/a*
- 如何秀出 /bin 底下,档名为四个字元的档案?
ls -l /bin/????
- 如何秀出 /bin 底下,档名开头不是 a-d 的档案?
ls -l /bin/[!a-d]*
- 当我离开 bash 后,希望系统可以帮我将最近工作的:1.)工作日期; 2.)100 个历史命令独立 记录到 ~/.bash_localcom 档案中,该如何设定?
我可以编辑 ~/.bash_logout ,将这个档案内容变成:
# ~/.bash_logout
date >> ~/.bash_localcom
history 100 >> ~/.bash_localcom
clear
参考资料
2002/06/27:第一次完成
2003/02/10:重新编排与加入 FAQ
2005/08/17:将旧的资料放置到 这里
2005/08/17:终于稍微搞定了~花了半个多月不眠不休~呼~补充了较多的管线命令与资料流重导向!
2005/08/18:加入额外的变数设定部分!
2005/08/30:加入了 login 与 non-login shell 的简单说明! - 如何显示 HOME 这个环境变数?
网络快照,版权归“http://linux.vbird.org”网站所有。
此页面仅供个人学习之用