认识 BASH Shell

               

                                                                                       
   
 
认识 BASH Shell
                       
最近更新日期:2005/08/30
                                                                                                                                   
文字模式 (command line) 这种指令下达的方式,在 Linux 里面,其实就相当于是 bash 的工具与介面! 因为 Linux 就是以 bash 为预设的 shell 的!那么前几章我们都已经很快乐的进行了很多的指令下达啰~ 所以说, bash shell 根本就不难吧~是啦!只要能够熟悉的话,那么确实他也不是这么不可亲近的一项工具啊~ 这个章节中,鸟哥会由变数谈起,先讲到环境变数的功能与修改的问题, 然后会继续提到历史指令的运用。接下来,就会谈一下‘资料流重导向’这个重要概念, 最后就是管线命令的利用啦!好好清一清脑门,准备用功去啰~ ^_^ 这个章节几乎是所有 command line 与未来主机维护与管理的重要基础,一定要好好仔细的阅读喔!
           
                       
大标题的图示Bash shell
           
我们在前面的 什么是 Linux 那个章节当中,提到了, 管理整个硬体的其实是核心 (kernel),那我们一般使用者 (user) 则是以 shell 来跟核心沟通~ 让核心达到我们所想要达到的工作目的。那么系统有多少 shell 可用呢? 为什么我们要使用 bash 啊?!底下分别来谈一谈喔!


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

硬体、核心与使用者的相关性图示
图一、硬体、核心与使用者的相关性图示

硬体、核心与使用者的相关性图示
图二、硬体、核心与使用者的相关性图示

基本上,替我们工作的是‘硬体’,而控制硬体的是‘核心’,再来,我们使用者乃是利用‘Shell’控制一些 kernel 提供的 ‘工具 (Utility)’来操控硬体替我们正确的工作。再进一步来说,由于 kernel 听不懂人类的语言,而人类也没有办法直接记得 kernel 的语言,所以两者的沟通就得藉由 shell 来支援了!( 其实早期的 DOS 的文字介面也是使用 shell 来沟通呀!那个 shell 的名称就叫做 command.com ,还记得吗? ^_^)

以字面上的意思来说, kernel 是‘核心’的意思,而 Shell 是‘壳’的意思,呵呵!也就是说, shell 是最外头的咚咚!而 kernel 乃是最内层的的咚咚啦!核心是作业系统的最底层的东西! 这个核心里头包括了各种的支援硬体的工具!当然啰,如果你的硬体太新,而你的 kernel 并没有支援的话,那么很抱歉,你的 Shell 能力再怎么强,也没有办法使硬体工作的! 这样可以了解了吗?呵呵!没错!使电脑主机工作的正是核心的任务,但是操作核心来替使用者工作的,却是 shell 喔!因此,有时候你的 shell 搞了老半天,硬体却不能工作的时候,请注意, 您的‘核心’是否正确呢?阿!扯远了!这是 kernel 章节才要说的东西。

           
  • 我干嘛要学习文字模式的 Shell 呢?           
    我们常常提到的 shell 其实是比较狭隘的定义,一般来说,在 Linux 里头,所谓的 shell 就是指 BASH 这个文字模式的 shell 啰。但是,广义的 shell 也可以是 KDE 之类的图形介面控制软体呢! 因为他也可以帮我们与 kernel 进行沟通啊!不过,在鸟哥的 Linux 私房菜里面, 如果没有特别说明的话,那么我们的 shell 指的是比较狭义的,也就是文字模式的 shell 喔!

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

    但是鸟哥在序章里面也已经提到过相当多次了, X Window 的介面虽然亲善,功能虽然强大,而 web 介面的工具也可以提供我们很友善的服务,但是毕竟他是将所有利用到的套件都整合在一起的一个套件而已, 并非是一个完整的套件,所以某些时候当你升级或者是使用其他套件管理模组( 例如 tarball 而非 rpm 档案等等 )时,就会造成设定的困扰了。

    此外,远端连线时, 文字介面的传输速度一定比较快, 而且,较不容易出现断线或者是资讯外流的问题,因此, shell 真的是得学习的一项工具。而且,他可以让您更深入 Linux ,更了解他, 而不是只会按一按滑鼠而已!所谓‘天助自助者!’多摸一点文字模式的东西,会让你与 Linux 更亲近呢!

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

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

    由于学习 shell 的好处真的是多多啦!所以,如果您是个系统管理员,或者有心想要管理系统的话,那么 shell 这个东西与 shell scripts 这个东西,真的真的有必要看一看!
               
  •            
           
小标题的图示 系统的 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:           
  •                
  • /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)
  •            
            由上面的说明中,我们大概可以发现,其实各主要 shell 的功能都差不多, 有的只是语法上面的不同而已。目前一般的使用者使用习惯上,似乎是以 bash 及 csh 为主要的两个 shell 。OK!这么多的 shell 我要使用哪一个啊?呵呵!使用 Linux 支援最广泛的 bash 就好了! 不要想太多!另外,咦! 为什么我们系统上的 shell 要写入 /etc/shells 这个档案啊? 这是因为系统某些服务在运行过程中, 会去检查使用者能够使用的 shells ,而这些 shell 的查询就是藉由 /etc/shells 这个档案啰!

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

那么,再想一想,我这个使用者什么时候可以取得 shell 来工作呢?还有, 我这个使用者预设会取得哪一个 shell 啊?!还记得我们在 首次进入 Linux -- 以文字方式登入 那个章节当中提到的登入动作吧?当我登入的时候,系统就会给我一个 shell 让我来工作了。 而这个登入取得的 shell 就记录在 /etc/passwd 这个档案内!这个档案的内容是啥?
                                                                                                                       
                       
[root@linux ~]# cat /etc/passwdroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin.....(中间省略).....
                       
            如上所示,在每一行的最后一个资料,就是您登入后,可以取得的预设的 shell 啦! 那你也会看到, root 是 /bin/bash ,不过,系统帐号 bin 与 daemon 等等,就使用那个怪怪的 /sbin/nologin 啰~关于使用者这部分的内容,我们留在 帐号管理 时提供更多的说明。

           
小标题的图示 Bash shell 的功能
           
既然 /bin/bash 是 Linux 预设的 shell ,那么总是得了解一下这个玩意儿吧! BASH 是怎么一回事呢?这个 shell 是 GNU 计画中重要的工具软体之一,目前也是 GNU 作业系统中标准的 shell ,他主要相容于 sh ,并且依据一些使用者需求,而加强的 shell 版本,可以说目前几乎所有的 Linux distribution 都是使用 bash 作为管理核心的主要 shell !因此,不论您使用的是那个 distribution ,你都难逃需要学习 bash 的宿命啦!那么这个 shell 有什么好处,干嘛 Linux 要使用他作为预设的 shell 呢? BASH 主要的优点有底下几个:

           
  • 命令编修能力(类似 DOS 的 doskey 功能):           
    使用 bash 里头,个人认为相当棒的一个功能就是‘他能记忆使用过的指令!’ 这功能真的相当的棒!因为我只要在指令列按‘上下键’就可以找到前一个输入的指令!而在很多 distribution 里头,预设的指令记忆功能可以到达 1000 个!也就是说, 你曾经下达过的指令都被记录下来了,记录的档案在你的家目录内的 .bash_history !不过,需要留意的是, ~/.bash_history 记录的是前一次登入以前所执行过的指令, 而至于这一次登入所执行的指令都被暂存在暂记忆体中,当您成功的登出系统后,该指令记忆才会记录到 .bash_history 当中

    这有什么功能呢?最大的好处就是可以‘ 查询曾经做过的举动!’, 如此可以知道你的执行步骤,那么就可以追踪您曾下达的指令,以作为除错的工具! 但如此一来也有个烦恼,就是如果被骇客入侵了,那么他只要翻你曾经执行过的指令, 刚好你的指令又跟系统有关(例如直接输入 MySQL 的密码在指令列上面)那么很容易就被破解你的 Linux 主机!所以, 最好是将记录的指令数目减小一点较好

               
  •            
  • 命令与档案补全功能:           
    还记得我们在 首次进入 Linux 的热门按键 一节当中提到的 [tab] 这个按键吗?!这个按键的功能就是在 bash 里头才有的啦!常常在 bash 环境中使用 [tab] 是个很棒的习惯喔!因为至少可以让你 1)少打很多字; 2)确定输入的资料是正确的! 使用 [tab] 按键的时机依据 [tab] 接在指令后或参数后而有所不同。我们再复习一次:           
    •                
    • [Tab] 接在一串指令的第一个字的后面,则为命令补全;
    •                
    • [Tab] 接在一串指令的第二个字以后时,则为‘档案补齐’!
    •                 所以说,如果我想要知道我的环境中,所有可以执行的指令有几个? 就直接在 bash 的提示字元后面输入两个 [tab][tab] 就能够输出所有的可执行指令了。 那如果想要知道系统当中所有以 c 为开头的指令呢?就按下 c[tab][tab] 就好啦! ^_^

      是的!真的是很方便的功能,所以, 有事没事,在 bash shell 底下,多按几次 [tab] 是一个不错的习惯啦

                   
                   
  •                
  • 命令别名(alias)设定功能:               
    假如我需要知道这个目录底下的所有档案(包含隐藏档)及所有的档案属性,那么我就必须要下达 ls -al 这样的指令列,唉!真麻烦,有没有更快的取代方式?呵呵!就使用命令别名呀!例如我最喜欢直接以 lm 这个自订的命令来取代上面的命令,也就是说, lm 会等于 ls -al 这样的一个功能,嘿!那么要如何作呢?就使用 alias 即可!你可以在指令列输入 alias 就可以知道目前的命令别名有哪些了!也可以直接下达命令来设定别名呦:               
    • alias lm='ls -al'
                       
                       
  •                    
  • 工作控制(jobs)、前景背景控制:                   
    这部分我们在之后的 资源管理章节中会再提及! 使用前、背景的控制可以让工作进行的更为顺利!至于工作控制(jobs)的用途则更广, 可以让我们随时将工作丢到背景中执行!而不怕不小心使用了 [Ctrl] + c 来停掉该程序!真是好样的!此外,也可以在单一登入的环境中,达到多工的目的呢!

                       
  •                    
  • Shell scripts 的强大功能:                   
    在 DOS 年代还记得将一堆指令写在一起的所谓的‘批次档’吧?在 Linux 底下的 shell scripts 则发挥的更为强大的功能,可以将您日常生活当中常需要下达的连续指令写成一个档案, 该档案并且可以透过对谈互动式的方式来进行主机的侦测工作!也可以藉由 shell 提供的环境变数及相关指令来进行设计,哇!整个设计下来几乎就是一个小型的程式语言了!该 scripts 的功能真的是超乎我的想像之外!以前在 DOS 底下需要程式语言才能写的东西,在 Linux 底下使用简单的 shell scripts 就可以帮你达成了!真的厉害!!这部分我们在后续章节再来谈!

                       
  •                    
  • 万用字元!                   
    除了完整的字串之外, bash 还支援许多的万用字元来帮助使用者查询与指令下达。 举例来说,想要知道 /usr/X11R6/bin 底下有多少以 xt 为开头的档案吗?使用: ls -l /usr/X11R6/bin/xt* 就能够知道啰~此外,还有其他可供利用的万用字元, 这些都能够加快使用者的操作呢!
                       
  •                    
                   
小标题的图示 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 这个指令来观察即可!举例来说:
                                                                                                                                                                               
                               
[root@linux ~]# type [-tpa] name参数:    :不加任何参数时,则 type 会显示出那个 name 是外部指令还是 bash 内建的指令!-t  :当加入 -t 参数时,type 会将 name 以底下这些字眼显示出他的意义:      file    :表示为外部指令;      alias   :表示该指令为命令别名所设定的名称;      builtin :表示该指令为 bash 内建的指令功能;-p  :如果后面接的 name 为指令时,会显示完整档名(外部指令)或显示为内建指令;-a  :会将由 PATH 变数定义的路径中,将所有含有 name 的指令都列出来,包含 alias范例:范例一:查询一下 ls 这个指令是否为 bash 内建?[root@linux ~]# type lsls is aliased to `ls --color=tty'# 没有加上任何参数,仅列出 ls 这个指令的最主要使用情况[root@linux ~]# type -t lsalias# -t 参数则仅列出 ls 这个指令的最主要使用情况说明[root@linux ~]# type -a lsls is aliased to `ls --color=tty'ls is /bin/ls# 利用所有方法找出来的 ls 相关资讯都会被列出来!范例二:那么 cd 呢?[root@linux ~]# type cdcd is a shell builtin
                               
                    透过 type 这个指令的用途,我们可以知道每个指令是否为 bash 的内建指令。 此外,由于利用 type 搜寻后面的名称时,如果后面接的名称并不能以执行档的状态被找到, 那么该名称是不会被显示出来的。举例来说,您的 FC4 应该不会有 vbird 这个指令吧?! 输入 type -p vbird 看一下,果然没有输出任何资料!而如果您输入的是 type -p touch 呢? 则会出现 /bin/touch !呵呵!所以, 这个 type 也可以用来作为类似 which 指令的用途啦!找指令用的!

                   
小标题的图示 指令的下达
                   
我们在 首次进入 Linux 一节当中,已经提到过在 shell 环境下的指令下达方式,不过,因为这个部分实在很重要,所以,我们还是再次的提醒一次!
                                                                                                                                                                               
                               
[root@linux ~]# command [-options] parameter1 parameter2 ...                  指令     选项      参数(1)    参数(2)说明:0. 一行指令中第一个输入的绝对是‘指令(command)’或‘可执行档案’1. command 为指令的名称,例如变换路径的指令为 cd 等等;2. 中刮号[]并不存在于实际的指令中,而加入参数设定时,通常为 - 号,例如 -h;   有时候完整参数名称会输入 -- 符号,例如 --help;3. parameter1 parameter2.. 为依附在 option 后面的参数,   或者是 command 的参数; 4. command, -options, parameter1.. 这几个咚咚中间以空格来区分,   不论空几格 shell 都视为一格; 5. 按下 [Enter] 按键后,该指令就立即执行。[Enter] 按键为 <CR> 字符,   他代表着一行指令的开始启动。6. 指令太长的时候,可以使用 / 符号来跳脱 [Enter] 符号,   使指令连续到下一行。注意! / 后就立刻接特殊字符。7. 在 Linux 系统中,英文大小写字母是不一样的。举例来说, cd 与 CD 并不同。范例:范例一:列出 /root 底下的各档案名称[root@linux ~]# ls -al /root[root@linux ~]# ls     -al      /root# 不论指令与参数中间空几格,都是可以接受的!范例二:如果指令太长的话,如何使用两行来输出?[root@linux ~]# cp /var/spool/mail/root /etc/crontab /> /etc/fstab /root# 上面这个指令,就是将三个档案复制到 /root 这个目录下而已。不过,因为指令太长,# 于是鸟哥就利用 /[Enter] 来将 [Enter] 这个按键‘跳脱!’开来,让# [Enter] 按键不再具有上述说明的第 5 点功能!好让指令继续在下一行输入。# 需要特别留意, [Enter] 按键是紧接着反斜线 (/) 的,两者中间没有其他字元。# 因为 / 仅跳脱‘紧接着的下一个字符’而已!所以,万一我写成:# / [Enter] ,亦即 [Enter] 与反斜线中间有一个空格时,则 / 跳脱的是‘空白键’# 而不是 [Enter] 按键!这个地方请在仔细的看一遍!很重要!# 如果顺利跳脱 [Enter] 后,下一行最前面就会主动出现 > 的符号,# 您可以继续输入指令啰!也就是说,那个 > 是系统自动出现的,你不需要输入。
                               
                    总之,当我们顺利的在终端机 (tty) 上面登入后, Linux 就会依据 /etc/passwd 档案的设定给我们一个 shell ,预设就是 bash ,然后我们就可以依据上面的指令下达方式来操作 shell, 之后,我们就可以透过 man 这个线上查询来查询指令的使用方式与参数说明, 很不错吧!那么我们就赶紧更进一步来操作 bash 这个好玩的东西啰!
                   
                   
大标题的图示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 这个变数的内容, 就能够自动的分辨出属于自己的信箱信件啰!这样一来,设计程式的设计师就真的很方便的啦!

当然我们可以改变这些个变数,但是如果该变数是直接深植于套件当中, 那么当你修改了某些参数之后,嘿嘿!你的套件就必须要‘ 由原始码直接更新再编译’ 才行!这样似乎很麻烦,所以啰,变数真的是很方便的啦!
                   
                                                                                                                                                                                                                               
Tips:
举个简单的例子来说, sendmail 的 smtp 存放 mail 路径是经由 /etc/profile 里头的:                               
  • MAIL="/var/spool/mail/$USER"
                                    来设定的,而当我修改了上面这一个咚咚,然后重新开机之后,嘿嘿嘿嘿! 我的邮件就可以存放到不同的路径去了!而且不会有问题!可以顺利的‘在 Linux 主机上面’收发。然而问题发生在 pop3 这个服务上面,由于 pop3 的预设路径是在 source code 里头,而且就正是 /var/spool/mail 这个路径,也就是说,不论我怎么修正我的‘变数’, pop3 都不为所动!唉~真惨,所以就无法直接以 pop3 来收信了(例如 OutLook 就不能工作了)!会发生密码不接受的问题呢!
                       
                        再来继续讲到其他的变数功能好了,我们前面已经提到过很多次,能不能执行某个指令, 与 PATH 这个变数也有很大的关系的。举例来说,我们在任何地方下达 ls 这个指令时,系统就是透过 PATH 这个变数里面的内容所记录的路径顺序来搜寻指令的呢!如果在搜寻完 PATH 变数内的路径还找不到 ls 这个指令时, 就会在萤幕上显示‘ command not found ’的错误讯息了。

这些还都只是系统预设的变数的目的,如果是个人的设定方面的应用呢:例如你要写一个大型的 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 的内容,该如何是好?
                                                                                                                                                                                                           
                                   
[root@linux ~]# echo $variable[root@linux ~]# echo $PATH/bin:/sbin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin[root@linux ~]# echo ${PATH}
                                   
                        变数的取用就如同上面的范例,利用 ehco 就能够读出,只是需要在变数名称前面加上 $ , 或者是以 ${variable} 的方式来取用都可以!当然啦,那个 echo 的功能可是很多的, 我们这里单纯是拿 echo 来读出变数的内容而已,更多的 echo 使用,请自行给他 man echo 吧! ^_^

                                                                                                                                                                                                                       
例题一:请在萤幕上面显示出您的环境变数 HOME 与 MAIL:
答:                                   
  • echo $HOME
    echo $MAIL
                                       
                           
OK!现在我们知道了变数与变数内的之间的相关性了,好了,那么我要如何‘设定’或者是‘修改’ 某个变数的内容啊?!很简单啦!用‘等号(=)’连接变数与他的内容就好啦!举例来说: 我要将 myname 这个变数名称的内容设定为 VBird ,那么:
                                                                                                                                                                                                                                       
                                       
[root@linux ~]# echo $myname   <==这里并没有任何资料~因为这个变数尚未被设定!是空的![root@linux ~]# myname=VBird[root@linux ~]# echo $mynameVBird  <==出现了!因为这个变数已经被设定了!
                                       
                            瞧!如此一来,这个变数名称 myname 的内容就带有 VBird 这个资料啰~ 而由上面的例子当中,我们也可以知道: 当一个变数名称尚未被设定时,预设的内容是‘空’的另外,变数在设定时,还是需要符合某些规定的,否则会设定失败喔! 这些规则如下所示啊!                           
  1.                                
  2. 变数与变数内容以等号‘=’来连结;
  3.                                
  4. 等号两边不能直接接空白字元;
  5.                                
  6. 变数名称只能是英文字母与数字,但是数字不能是开头字元;
  7.                                
  8. 若有空白字元可以使用双引号‘ " ’或单引号‘ ' ’来将变数内容结合起来,但须要特别留意, 双引号内的特殊字元可以保有变数特性,但是单引号内的特殊字元则仅为一般字元;
  9.                                
  10. 必要时需要以跳脱字元‘ / ’来将特殊符号 ( 如 Enter, $, /, 空白字元, ' 等 ) 变成一般符号;
  11.                                
  12. 在一串指令中,还需要藉由其他的指令提供的资讯,可以使用 quote ‘ ` command` ’;(特别特别注意,那个 ` 是键盘上方的数字键 1 左边那个按键,而不是单引号!)
  13.                                
  14. 若该变数为扩增变数内容时,则需以双引号及 $变数名称 如:‘ "$PATH":/home’继续累加内容;
  15.                                
  16. 若该变数需要在其他子程序执行,则需要以 export 来使变数变成环境变数, 如‘export PATH’;
  17.                                
  18. 通常大写字元为系统预设变数,自行设定变数可以使用小写字元,方便判断 ( 纯粹依照使用者兴趣与嗜好 ) ;
  19.                                
  20. 取消变数的方法为:‘unset 变数名称’。
  21.                                 底下我们举几个例子来让您试看看,就知道怎么设定好您的变数啰!
                                                                                                                                                                                                                                                                       
                                               
    范例一:设定一变数 name ,且内容为 VBird 。[root@linux ~]# 12name=VBird-bash: 12name=VBird: command not found  <==萤幕会显示错误!因为不能以数字开头![root@linux ~]# name = VBird  <==还是错误!因为有空白![root@linux ~]# name=VBird    <==OK 的啦!范例二:呈上题,若变数内容为 VBird's name 呢?[root@linux ~]# name=VBird's name  # 因为单引号可以将 Enter 这个特殊字符取消,所以,您可以继续在下一行输入内容~# 不过,这与我们要达到的功能不同,所以,算是失败的啦![root@linux ~]# name="VBird's name"  <==OK 的啦![root@linux ~]# name=VBird/'s/ name# 利用反斜线 (/) 跳脱特殊字元,例如单引号与空白键,这也是 OK 的啦!范例三:我要在 PATH 这个变数当中‘累加’:/home/dmtsai/bin 这个目录[root@linux ~]# PATH=$PATH:/home/dmtsai/bin[root@linux ~]# PATH="$PATH":/home/dmtsai/bin# 上面这两种格式在 PATH 里头的设定都是 OK 的!但是底下的例子就不见得啰!范例四:呈范例三,我要将 name 的内容多出 "yes" 呢?[root@linux ~]# name=$nameyes  # 知道了吧?如果没有双引号,那么变数成了啥?name 的内容是 $nameyes 这个变数!# 呵呵!我们可没有设定过 nameyes 这个变数呐!所以,应该是底下这样才对![root@linux ~]# name="$name"yes[root@linux ~]# name=${name}yes范例五:如何让我刚刚设定的 name=VBird 可以用在下个 shell 的程序?[root@linux ~]# name=VBird[root@linux ~]# bash        <==进入到所谓的子程序[root@linux ~]# echo $name  <==嘿嘿!并没有刚刚设定的内容喔![root@linux ~]# exit        <==离开刚刚的子程序[root@linux ~]# export name[root@linux ~]# bash        <==进入到所谓的子程序[root@linux ~]# echo $name  <==出现了设定值了![root@linux ~]# exit        <==离开刚刚的子程序# 什么是‘子程序’呢?就是说,在我目前这个 shell 的情况下,# 去启用另一个新的 shell ,新的那个 shell 就是子程序啦!在一般的状态下,# 父程序的自订变数是无法在子程序内使用的。但是透过 export 将变数变成# 环境变数后,就能够在子程序底下应用了!很不赖吧!至于程序的相关概念,# 我们会在‘程序与资源管理’章节当中提到的喔!范例六:如何进入到您目前核心的模组目录?[root@linux ~]# cd /lib/modules/`uname -r`/kernel# 每个作业系统核心版本都不相同,以 FC4 为例,他的预设核心版本是 # 2.6.11-1.1369_FC4 所以,他的模组目录在 /lib/modules/2.6.11-1.1369_FC4/kernel 。# 因为每个 distributions 的这个值都不相同,但是我们却可以利用 uname -r 这个指令# 先取得版本资讯,所以啰,就可以透过上面指令当中的内含指令 `uname -r` # 先取得版本输出到 cd .. 那个指令当中,就能够顺利的进入目前核心的驱动程式所放置# 的目录啰!很方便吧!范例七:取消刚刚设定的 name 这个变数内容[root@linux ~]# unset name
                                               
                                    根据上面的案例你可以试试看!就可以了解变数的设定啰!这个是很重要的呦!请勤加练习!! 其中,较为重要的一些特殊符号的使用啰!例如单引号、双引号、跳脱字元、钱字号、quote 符号等等,底下的例题想一想吧!

                                                                                                                                                                                                                                                                                               
    例题二:在变数的设定当中,单引号与双引号的用途有何不同?
    答:                                           
    • 单引号与双引号的最大不同在于 双引号仍然可以保有变数的内容,但单引号内仅能是一般字元 ,而不会有特殊符号。我们以底下的例子做说明:假设您定义了一个变数, name=VBird ,现在想以 name 这个变数的内容定义出 myname 显示 VBird its me 这个内容,要如何订定呢?                                               

      • [root@linux ~]# name=VBird
        [root@linux ~]# echo $name
        VBird
        [root@linux ~]# myname="$name its me"
        [root@linux ~]# echo $myname
        VBird its me
        [root@linux ~]# myname='$name its me'
        [root@linux ~]# echo $myname
        $name its me
        发现了吗?没错!使用了单引号的时候,那么 $name 将失去原有的变数内容, 仅为一般字元的显示型态而已!这里必需要特别小心在意!
                                                         
                                                       
                                           
                                                                                                                                                                                                                                                                                                                                                       
    例题三:在指令下达的过程中, quote ( ` ) 这个符号代表的意义为何?
    答:                                                   
    • 在一串指令中,在 ` 之内的指令将会被先执行,而其执行出来的结果将做为外部的输入资讯!例如 uname -r 会显示出目前的核心版本,而我们的核心版本在 /lib/modules 里面,因此,你可以先执行 uname -r 找出核心版本,然后再以‘ cd 目录’到该目录下,当然也可以执行如同上面范例六的执行内容啰。

      另外再举个例子,我们也知道, locate 指令可以列出所有的相关档案档名,但是, 如果我想要知道各个档案的权限呢?举例来说,我想要知道每个 crontab 相关档名的权限:                                                       

      • [root@linux ~]# ls -l `locate crontab`如此一来,先以 locate 将档名资料都列出来,再以 ls 指令来处理的意思啦!了了吗? ^_^
                                                                 
                                                               
                                                   
                                               
                                               
小标题的图示 变数的用途
                                               
我们知道 PATH 这个变数是我们在执行指令的时候,所需要具备的指令搜寻目录资料, 没有他,我们就得要使用绝对路径来下达指令才行。当然,还有很多变数都有他特别的意义存在。 除此之外,‘ 我为何需要设定变数’呢? 要跟大家介绍这个‘变数’,当然是因为他有相当程度的意义存在的啊! 底下就跟大家介绍一下,鸟哥设定变数的时机喔!                                               
  • 我的案例一:最简单的例子就是 ‘ 简化路径名称’啰!以鸟哥为例,我的工作在 Unix 系统之下进行一些数值模式的模拟工作,偏偏由于资料量太大, 为了怕日后忘记这个目录的内容与主要的意义,所以我的档名都取的很长, 偏偏在执行模式的过程中,常常会切换目录!我哩ㄌㄟ,光是打那几行路径名称就快要疯掉了! 所以我就设定那几行目录名称成为一个四个字元的变数,如此一来我只要输入‘ cd $VARI ’这个指令,嘿嘿!马上就移动到该路径下了!很方便吧!当然变数的意义还不止于此, 不过这是最简单的实例说明啰!
                                                   
  • 我的案例二:另外一个常常需要变数的咚咚是在 scripts 里面,例如我写的一个侦测登录档的小程式 logfile.sh 这个咚咚, 由于里头常常需要用到‘储存路径’,偏偏可能每个人的存取路径都不太一样, 而如果要修改存取路径的话,嘿嘿!好几十行要同时修改呢!还可能会改错! 那么我只要定义一个变数,然后后续的所有资料都使用这个变数的内容!嘿嘿! 那么只要大家修改了这个变数的内容(只要一行),后续的动作就不需要修正了!这个动作常在程式或者是 script 当中看到的!
                                                        所以啰,有很多的时候为了方便或者是使用于 scripts 的意义,我们必须要设定变数! 当然啰,如果是跟系统终端机环境有关的设定值,很多也是利用变数来帮助达成的~ 底下我们就来谈一谈所谓的‘环境变数’吧!

                                                       
小标题的图示 环境变数的功能
                                                       
环境变数可以帮我们达到很多功能~包括家目录的变换啊、提示字元的显示啊、执行档搜寻的路径啊等等的, 还有很多很多啦!那么,既然环境变数有那么多的功能,问一下,目前我的 shell 环境中, 有多少变数啊?!呵呵!我们可以利用两个指令来查阅,分别是 env 与 export 呢!


                                                       
  • 一些环境变数的说明: env                                                        
                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                       
    范例一:列出目前的 shell 环境下的所有环境变数与其内容。[root@linux ~]# envHOSTNAME=linux.dmtsai.tw   <== 这部主机的主机名称SHELL=/bin/bash            <== 目前这个环境下,使用的 Shell 是哪一个程式?TERM=xterm                 <== 这个终端机使用的环境是什么类型HISTSIZE=1000              <== 这个就是‘记录指令的笔数’在 FC4 预设可记录 1000 笔USER=root                  <== 使用者的名称啊!LS_COLORS=no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=00;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz=00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;31:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00;35:*.xpm=00;35:*.png=00;35:*.tif=00;35: <== 一些颜色显示ENV=/root/.bashrc          <== 使用的个人环境设定档MAIL=/var/spool/mail/root  <== 这个使用者所取用的 mailbox 位置PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin:/root/bin                  <== 不再多讲啊!是执行档指令搜寻路径INPUTRC=/etc/inputrc       <== 与键盘按键功能有关。可以设定特殊按键!PWD=/root                  <== 目前使用者所在的工作目录 (利用 pwd 取出!)LANG=en_US.UTF-8           <== 这个与语系有关,底下会再介绍!HOME=/root                 <== 这个使用者的家目录啊!_=/bin/env                 <== 上一次使用的指令的最后一个参数(或指令本身)
                                                                       
                                                            env 是 environment (环境) 的简写啊~ 上面的例子当中,是列出来所有的环境变数。当然,如果使用 export 也会是一样的内容~ 只不过, export 还有其他额外的功能就是了,我们等一下再提这个 export 指令。 那么上面这些变数有些什么功用呢? 底下我们就一个一个来分析分析!                                                       
    •                                                            
    • HOME : 代表使用者的家目录。还记得我们可以使用 cd ~ 去到使用者的家目录吗?或者利用 cd 就可以直接回到使用者家目录了。那就是取用这个功能啦~ 有很多程式都可能会取用到这个变数的值喔!
    •                                                            
    • SHELL : 告知我们,目前这个环境使用的 SHELL 是哪支程式? 如果是 bash 的话,预设是 /bin/bash 的啦!
    •                                                            
    • HISTSIZE : 这个与‘历史命令’有关,亦即是, 我们曾经下达过的指令可以被系统记录下来,而记录的‘笔数’则是由这个值来设定的。
    •                                                            
    • ENV : 这个使用者所使用的个人化环境设定档的读取档案。
    •                                                            
    • MAIL : 当我们使用 mail 这个指令在收信时,系统会去读取的邮件信箱档案 (mailbox)。
    •                                                            
    • PATH : 就是执行档搜寻的路径啦~目录与目录中间以冒号(:)分隔, 由于档案的搜寻是依序由 PATH 的变数内的目录来查询,所以,目录的顺序也是重要的喔。
    •                                                            
    • LANG : 这个重要!就是语系档案啰~很多资料都会用到他, 举例来说,当我们在启动某些 perl 的程式语言档案时,他会主动的去分析语系资料档案, 如果发现有他无法解析的编码语系,可能会产生错误喔!一般来说,我们中文编码通常是 zh_TW.Big5 或者是 zh_TW.UTF-8,这两个编码偏偏不容易被解译出来,所以,有的时候,可能需要修订一下语系资料。 这部分我们会在下个小节做介绍的!
    •                                                            
    • RANDOM : 这个玩意儿就是‘随机乱数’的变数啦!目前大多数的 distributions 都会有乱数产生器,那就是 /dev/random 这个档案。 我们可以透过这个乱数档案相关的变数 ($RANDOM) 来随机取得乱数值喔。在 BASH 的环境下,这个 RANDOM 变数的内容,介于 0~32767 之间,所以,你只要 echo $RANDOM 时,系统就会主动的随机取出一个介于 0~32767 的数值。万一我想要使用 0~9 之间的数值呢?呵呵~利用 declare 宣告数值类型, 然后这样做就可以了:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
                                                                             
      [root@linux ~]# declare -i number=$RANDOM*10/32767 ; echo $number8   <== 此时会随机取出 0~9 之间的数值喔!
                                                                             
                                                                 
    •                                                        
                                                            大致上是有这些环境变数啦~里面有些比较重要的参数,在底下我们都会另外进行一些说明的~
                                                           
  •                                                        
  • 其他所有的变数说明: set                                                       
    而除了这些环境变数之外,还有没有什么重要的变数呢?当然有啊! 我们在 bash 的环境下,其实还有一些挺重要的变数,这些变数是‘ 在这个 shell 环境下有效’的, 如果是在‘子程序’,这些变数值就不会相同了。 那么如何观察目前 shell 环境下的所有变数呢?很简单啊,就用 set 即可!set 这个指令除了会将环境变数列出来之外,其他我们的自订变数,与所有的变数,都会被列出来喔!资讯多好多。 底下仅列出几个重要的内容。
                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                       
    [root@linux ~]# setBASH=/bin/bash           <== bash 的主程式放置路径BASH_VERSINFO=([0]="3" [1]="00" [2]="16" [3]="1" [4]="release" [5]="i386-redhat-linux-gnu")      <== bash 的版本啊!BASH_VERSION='3.00.16(1)-release' <== bash 的版本啊!COLORS=/etc/DIR_COLORS.xterm      <== 使用的颜色纪录档案COLUMNS=115              <== 在目前的终端机环境下,使用的栏位有几个字元长度HISTFILE=/root/.bash_history      <== 历史命令记录的放置档案,隐藏档HISTFILESIZE=1000        <== 存起来(与上个变数有关)的档案之指令的最大纪录笔数。HISTSIZE=1000            <== 目前环境下,可记录的历史命令最大笔数。HOSTTYPE=i386            <== 主机安装的软体主要类型。我们用的是 i386 相容机器软体IFS=
                                                                       
                                                            一般来说,不论是否为环境变数,只要跟我们目前这个 shell 的操作介面有关的变数, 通常都会被设定为大写字元,也就是说,‘ 基本上,在 Linux 预设的情况中,使用{大写的字母}来设定的变数一般为系统内定需要的变数’。

    使用 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 呢?可以这样啊:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                         
          [root@linux home]# PS1='[/u@/h /w /A #/#]/$ '[root@linux /home 17:02 #85]# # 看到了吗?提示字元变了!变的很有趣吧!其中,那个 #85 比较有趣,# 如果您按下 [Enter] 后,该数字就会增加喔!为啥?上面有说明ㄇㄟ!
                                                                                         
                                                                             
                                                                       
                                                                     
    •                                                                
    • $:(关于本 shell 的 PID)

      其实这个咚咚代表的是‘目前这个 Shell 的执行绪代号’,亦即是所谓的 PID (Process ID)。 更多的程序观念,我们会在第四章的时候提及。想要知道我们的 shell 的 PID ,就可以: echo $$ 即可!
    •                                                                
    • ?:(关于上个执行指令的回传码)

      虾密?问号也是一个特殊的变数?没错!在 bash 里面这个变数可重要的很! 这个变数是:‘上个执行的指令所回传的值’, 上面这句话的重点是‘上一个指令’与‘回传值’两个地方。当我们执行某些指令时, 这些指令都会回传一个执行后的代码。一般来说,如果成功的执行该指令, 则会回传一个 0 值,如果执行过程发生错误,就会回传‘错误代码’才对!一般就是以非为 0 的数值来取代。 我们以底下的例子来看看:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                 
      [root@linux ~]# echo $SHELL/bin/bash[root@linux ~]# echo $?0# 因为上个指令执行过程中,并没有错误,为成功的执行完毕,所以回传 0 。[root@linux ~]# 12name=VBird-bash: 12name=VBird: command not found[root@linux ~]# echo $?127# 发生错误啦!所以 echo $? 时,就会出现错误的代码!# 我们可以利用这个代码来搜寻错误的原因喔![root@linux ~]# echo $?0# 咦!怎么又变成正确了?这是因为 "?" 只与‘上一个执行指令’有关,# 所以,我们上一个指令是执行‘ echo $? ’,当然没有错误,所以是 0 没错!
                                                                                 
                                                                     
    •                                                                
    • OSTYPE, HOSTTYPE, MACHTYPE:(主机硬体与核心的等级)

      这几个东西与程式的安装有关。我们在‘Linux 主机规划’ 里面提到过关于主机的等级方面的问题,当我们在安装软体的时候, 需要透过编译器来将原始码编译成为二进位的档案 (binary file)。但是, 我们可以针对硬体的配备来进行编译的最佳化,此时,这些参数就可以被用到了! 基本上,目前主要的 distribution 都是针对 i386 亦即最低等级的机器进行最佳化, 这样才能够安装在较高阶的机器上,如果以 686 的机型来最佳化, 那么,可就无法向下相容的喔!(早期的 OpenLinux 是针对 686 机器来释出软体, 所以,当时的 OpenLinux 是无法安装在 P-166 的机器上的。 )
    •                                                            
                                                               
                                                               
    自订变数转成环境变数: export                                                           
    好了,上面我们环境变数也提过了,一些自订变数也提过了,那么,这两者有啥不同? 他的不同处,我们在 变数设定规则 当中稍微提过, 主要是由于变数可否被子程序所引用。

    当你取得一个 bash 之后,亦即得到了一个程序了,但是若你再次的执行一次 bash ,那么你将进入‘子程序’,这个程序的概念我们在资源管理章节中再详谈,这里您先有个概念即可。 那么 由于您已经进入了该子程序,所以在父程序中的自订变数设定将不再继续的存在。 会存在子程序中的,仅有‘环境变数’

    换个角度来想,也就是说,如果我能将自订变数变成环境变数的话,那不就可以让该变数值继续存在于子程序了? 呵呵!没错!此时,那个 export 指令就很有用啦! 如您想要让该变数内容继续的在子程序中使用,那么就请执行:                                                           
    • export 变数
                                                                    这个东西用在‘ 引用他人的档案或者其他程序’时,相当的重要的! 尤其像鸟哥常常两三个档案互相引用来引用去的,如果忘记设定 export 的话,那么不同的档案中的相同变数值,将需要一再地重复设定才行!所以,我只要在头一个档案使用 export 的话,那么后续的档案引用时,将会把该变数内容读进来!好用的很,如果仅下达 export 而没有接变数时,那么此时将会把所有的‘环境变数’秀出来喔!例如:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                               
    [root@linux ~]# exportdeclare -x ENV="/root/.bashrc"declare -x HISTSIZE="1000"declare -x HOME="/root"declare -x HOSTNAME="linux.dmtsai.tw"declare -x INPUTRC="/etc/inputrc"declare -x LANG="en_US.UTF-8"declare -x MAIL="/var/spool/mail/root"declare -x SHELL="/bin/bash"# 很多都直接省略了!不然....重复性太高,浪费版面~ ^_^
                                                                               
                                                                   
                                                                   
  •                                                                
                                                               
小标题的图示 语系档案的变数 (locale)
                                                               
还记得我们在首次进入 Linux 那个章节里面提到的,关于语系编码的问题吗? 就是当我们使用 man command 的方式去查询某个资料的说明档时,该说明档的内容可能会因为我们使用的语系, 而产生一些乱码。另外,利用 ls 查询档案的时间时,也可能会有乱码出现在时间的部分。 那个问题其实就是语系的问题啦。

目前大多数的 Linux distributions 已经都是支援万国码,此外,也都支援大部分的语言语系了。 这有赖于 i18n 支援的帮助呢! 那么我们的 Linux 到底支援了多少的语系呢?这可以由 locale 这个指令来查询到喔!
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                           
[root@linux ~]# locale -aaa_DJaa_DJ.iso88591en_USen_US.iso88591en_US.iso885915en_US.utf8zh_TWzh_TW.big5zh_TW.euctwzh_TW.utf8# 其实输出的内容有很多,鸟哥将一些资讯舍弃了~# 从上面的输出中,我们也不难看出,系统是有支援 big5, utf8 等中文语系资料的!
                                                                           
                                                                中文语系至少支援了两种以上的编码,一种是目前还是很常见的 big5 ,另一种则是越来越热门的 utf-8 编码。 那么我们如何修订这些编码呢?其实可以透过底下这些变数的说:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                           
[root@linux ~]# LANG         <==主语言的环境[root@linux ~]# LC_CTYPE     <==字元辨识的编码[root@linux ~]# LC_NUMERIC   <==数字系统的显示讯息[root@linux ~]# LC_TIME      <==时间系统的显示资料[root@linux ~]# LC_COLLATE   <==字串的比较与排序等[root@linux ~]# LC_MONETARY  <==币值格式的显示等[root@linux ~]# LC_MESSAGES  <==讯息显示的内容,如功能表、错误讯息等[root@linux ~]# LC_ALL       <==语言环境的整体设定。
                                                                           
                                                                基本上,你可以逐一设定每个与语系有关的变数资料,但事实上,如果其他的语系变数都未设定, 且您有设定 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 这个档案呢! 这个档案的内容有点像这样:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                           
[root@linux ~]# vi /etc/sysconfig/i18nLANG="en_US.UTF-8"SYSFONT="latarcyrheb-sun16"SUPPORTED="zh_TW.UTF-8:zh_TW:zh:en_US.UTF-8"
                                                                           
                                                                你可以在这个档案当中加入 LC_TIME 或者其他语系相关变数的设定内容, 也可以直接修改 LANG 那个变数即可啊! ^_^ 但,事实上,我们还可以透过个人的环境设定档来设定 LANG 呢! 如此一来,则不必修订系统的语系档案,比较安全啦!
                                                               
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
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 ,作业系统分配一记忆区块给 shell 使用,此区域之变数可以让子程序存取;
  •                                                                    
  • 利用 export 功能,可以让变数的内容写到上述的记忆区块当中(环境变数);
  •                                                                    
  • 当载入另一个 shell 时 (亦即启动子程序,而离开原本的父程序了),子 shell 可以将父 shell 的环境变数所在的记忆区块导入自己的环境变数区块当中。
  •                                                                
                                                                透过这样的关系,我们就可以让某些变数可以在相关的程序之间存在,以帮助自己更方便的操作环境喔!
                                                               
小标题的图示 变数键盘读取、阵列与宣告: read, array, declare
                                                               
我们上面提到的变数设定功能,都是直接由指令列直接设定的,那么,可不可以让使用者能够经由键盘输入? 什么意思呢?是否记得某些程式执行的过程当中,会等待使用者输入 "yes/no" 之类的讯息啊!? 在 bash 里面也有相对应的功能喔!此外,我们还可以宣告这个变数的属性, 例如:阵列或者是数字等等的。底下就来看看吧!


                                                               
  • read                                                               
    要读取来自键盘输入的变数,就是用 read 这个指令了。这个指令最常被用在 shell script 的撰写当中, 以跟使用者进行对谈。关于 script 的写法,我们会在后面章节介绍,底下先来瞧一瞧 read 的相关语法吧!
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                               
    [root@linux ~]# read [-pt] variable参数:-p  :后面可以接提示字元!-t  :后面可以接等待的‘秒数!’这个比较有趣~不会一直等待使用者啦!范例:范例一:让使用者由键盘输入一内容,将该内容变成 atest 变数[root@linux ~]# read atestThis is a test[root@linux ~]# echo $atestThis is a test范例二:提示使用者 30 秒内输入自己的大名,将该输入字串做成 named 变数[root@linux ~]# read -p "Please keyin your name: " -t 30 namedPlease keyin your name: VBird Tsai[root@linux ~]# echo $namedVBird Tsai
                                                                               
                                                                    read 之后不加任何参数,直接加上变数名称,那么底下就会主动出现一个空白行,等待您输入。 如果加上 -t 后面接秒数之后,例如上面的范例当中,那么 30 秒之内没有任何动作时, 该指令就会自动略过了~如果是加上 -p ,嘿嘿!后面就会有比较多可以用的提示字元给我们参考! 在指令的下达里面,比较美观啦! ^_^

                                                                   
  •                                                                
  • declare / typeset                                                               
    declare 或 typeset 是一样的功能,就是在宣告变数的属性。如果使用 declare 后面并没有接任何参数, 那么 bash 就会主动的将所有的变数名称与内容通通叫出来,就好像使用 set 一样啦! 那么 declare 还有什么语法呢?看看先:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                               
    [root@linux ~]# declare [-aixr] variable参数:-a  :将后面的 variable 定义成为阵列 (array)-i  :将后面接的 variable 定义成为整数数字 (integer)-x  :用法与 export 一样,就是将后面的 variable 变成环境变数;-r  :将一个 variable 的变数设定成为 readonly ,该变数不可被更改内容,也不能 unset范例:范例一:让变数 sum 进行 100+300+50 的加总结果[root@linux ~]# sum=100+300+50100+300+50  <==咦!怎么没有帮我计算加总?因为这是文字型态的变数属性啊![root@linux ~]# echo $sum[root@linux ~]# declare -i sum=100+300+50[root@linux ~]# echo $sum450         <==了乎??范例二:将 sum 变成环境变数[root@linux ~]# declare -x sum范例三:让 sum 变成唯读属性,不可更动![root@linux ~]# declare -r sum[root@linux ~]# sum=tesgting-bash: sum: readonly variable  <==老天爷~不能改这个变数了!
                                                                               
                                                                    declare 也是个很有用的功能~尤其是当我们需要使用到底下的阵列功能时, 他也可以帮我们宣告阵列的属性喔!不过,老话一句,阵列也是在 shell script 比较常用的啦!

                                                                   
  •                                                                
  • 阵列属性 array 说明                                                               
    某些时候,我们必须使用阵列来宣告一些变数,这有什么好处啊?在一般人的使用上, 果然是看不出来有什么好处的!不过,如果您曾经写过程式的话,那才会比较了解阵列的意义~ 阵列对写数值程式的设计师来说,可是不能错过学习的重点之一哩!好!不啰唆~ 那么要如何设定阵列的变数与内容呢?在 bash 里头,阵列的设定方式是:                                                               
    • var[index]=content
                                                                        意思是说,我有一个阵列名称为 var ,而这个阵列的内容为 var[1]=小明, var[2]=大明, var[3]=好明 .... 等等,那个 index 就是一些数字啦,重点是用中刮号 ([ ]) 来设定的。 目前我们 bash 提供的是一维阵列。老实说,如果您不必写一些复杂的程式, 那么这个阵列的地方,可以先略过,等到有需要再来学习即可!因为要制作出阵列, 通常与回圈或者其他判断式交互使用才有比较高的意义存在!
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                                   
    范例:设定上面提到的 var[1] ~ var[3] 的变数。[root@linux ~]# var[1]="small min"[root@linux ~]# var[2]="big min"[root@linux ~]# var[3]="nice min"[root@linux ~]# echo "${var[1]}, ${var[2]}, ${var[3]}"
                                                                                   
                                                                        比较有趣的地方在于‘读取’,一般来说,建议直接以 ${阵列} 的方式来读取, 比较正确无误的啦!
                                                                       
  •                                                                    
                                                                   
小标题的图示 与档案系统及程序的限制关系: ulimit
                                                                   
想像一个状况:我的 Linux 主机里面同时登入了十个人,这十个人不知怎么搞的, 同时开启了 100 个档案,每个档案的大小约 10MBytes ,请问一下, 我的 Linux 主机的记忆体要有多大才够? 10*100*10 = 10000 MBytes ~~ 老天爷,这样,系统不挂点才有鬼哩!为了要预防这个情况的发生,所以, 我们的 bash 是可以‘限制使用者的某些系统资源’的,包括可以开启的档案数量, 可以使用的 CPU 时间,可以使用的记忆体总量等等。如何设定?用 ulimit 吧!
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
                                                                               
[root@linux ~]# ulimit [-SHacdflmnpstuv] [配额]参数:-H  :hard limit ,严格的设定,必定不能超过设定的值;-S  :soft limit ,警告的设定,可以超过这个设定值,但是会有警告讯息,      并且,还是无法超过 hard limit 的喔!也就是说,假设我的 soft limit      为 80 , hard limit 为 100 ,那么我的某个资源可以用到 90 ,      可以超过 80 ,还是无法超过 100 ,而且在 80~90 之间,会有警告讯息的意思。-a  :列出所有的限制额度;-c  :可建立的最大核心档案容量 (core files)-d  :程序资料可使用的最大容量-f  :此 shell 可以建立的最大档案容量 (一般可能设定为 2GB)单位为 Kbytes-l  :可用于锁定 (lock) 的记忆体量-p  :可用以管线处理 (pipe) 的数量-t  :可使用的最大 CPU 时间 (单位为秒)-u  :单一使用者可以使用的最大程序(process)数量。范例:范例一:列出所有的限制资料[root@linux ~]# ulimit -a范例二:限制使用者仅能建立 1MBytes 以下的容量的档案[root@linux ~]# ulimit -f 1024
                                                                               
                                                                    还记得我们在 Linux 磁碟档案系统 里面提到过,单一 filesystem 能够支援的单一档案大小与 block 的大小有关。例如 block size 为 1024 byte 时,单一档案可达 16GB 的容量。但是,我们可以用 ulimit 来限制使用者可以建立的档案大小喔! 利用 ulimit -f 就可以来设定了!例如上面的范例二,要注意单位喔!单位是 Kbytes。 若改天你一直无法建立一个大容量的档案,记得瞧一瞧 ulimit 的资讯喔!( 不过,要注意的是,一般身份使用者如果以 ulimit 设定了 -f 的档案大小, 那么他‘只能减小档案大小,不能增加档案大小喔!’)
                                                                   
小标题的图示 额外的变数设定功能
                                                                   
刚刚我们提到了两种变数取用的方法,分别是这样:
                                                                                                                                                                                                                                                                                                       
                                

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值