我们比较关心的可能是这样的一行
PATH="$PATH:/usr/X11R6/bin:/usr/sbin/:./"
通过下边的export语句,这一句就象dos中设置path路径一样,所不同的主要有以下三点:
a、形式上用冒号分隔各个路径单元,不象dos是用分号分隔;
b、内容上可以使用$PATH代替这个赋值等式前的路径设置(注意,linux是区分大小写的);
c、效果上这个路径决定了bash查找的绝对范围,不要认为bash会象dos自动先查找当前路径,除非你在PATH中进行了设置。
你可以使用echo $PATH来显示自己的当前PATH设置。
关于bash更详细的帮助可以通过man bash命令获得。
再继续研究 BASH 之前,我们要就变量这个东西来讨论一番,因为在主机里面有太多的数据需要进行存取了,而这些数据都是一些服务所必须的,例如 mail 的存取路径在 /var/spool/mail 、家目录预设在 /home/useraccount 等等,当然我们可以改变这些个变量,但是如果该变量是直接深植于套件当中,那么当你修改了某些参数之后,嘿嘿!你的套件就必须要『由原始码直接更新再编译』才行!这样似乎很麻烦,所以啰,就会有变量这个好东西出来了!此外,例如我们在执行程序的时候,系统怎么知道你的 ls 这个指令放在哪里?原来是有 PATH 这个变量,系统会透过这个变量里面所设定的路径去依序寻找该指令系统,如果找不到的话,那么才在屏幕上显示『 command not found 』字样!这些还都只是系统预设的变量的目的,如果是个人的设定方面:例如你要写一个大型的 script (批次文件)时,有些数据因为可能由于使用者习惯的不同而有差异,比如说路径好了,由于该路径在 script 被使用在相当多的地方,如果下次换了一部主机,都要修改 script 里面的所有路径,那么我一定会疯掉!这个时候如果使用变量,而将该变量的定义写在最前面,后面相关的路径名称都以变量来取代,嘿嘿!那么你只要修改一行就等于修改整篇 script 了!方便的很!所以,良好的程序设计师都会善用变量的定义!(这个部分我们在底下还会再提到!)
如果说的学理一点,那么由于在 Linux System 下面,所有的执行续都是需要一个执行码,而就如同上面提到的,你『真正以 shell 来跟 Linux 沟通,是在正确的登入 Linux 之后!』这个时候你就有一个 bash 的执行程序,也才可以真正的经由 bash 来跟系统沟通啰!而在进入 shell 之前,也正如同上面提到的,由于系统需要一些变量来提供他数据的存取(或者是一些环境的设定参数值,例如是否要显示彩色等等的),所以就有一些所谓的『环境变量』需要来读入系统中了!这些环境变量例如 PATH、HOME、MAIL、SHELL等等,都是很重要的,为了区别与自订变量的不同,环境变量通常以大写字符来表示呢!
说了那么久,那么到底『什么是变量』呢?简单的说,『变量就是以一组文字或符号等,来取代一些设定或者是一串保留的数据!』,例如:『VBird』就是『鸟哥』,所以当你读取 VBird 的时候,系统自然就会知道!哈!那就是鸟哥!最简单的例子可以取 PATH 来说明!如果你对于『相对路径与绝对路径』还有点印象的话,那么应该晓得『要下达正确的指令,应该需要指定路径与文件名』才行!例如你的 ls 指令应该需要以『/bin/ls』来下达指令才对,那么为何你在任意的路径下都可以执行 ls 呢?而不需要指定路径呢?这是因为系统已经预设了一些『搜寻路径(PATH)』了,所以当你需要执行一些指令的时候,系统就会依照该 PATH 的设定来进行指令的搜寻!而这个 PATH 就是所谓的变量了!那么如何『显示变量』呢?这就需要使用到 echo 这个指令啦!
- env
显示目前系统中主要的预设变量内容
语法: env environment 的简写,所以说,这个指令主要在将目前系统中的主要变量读出来!但是,不是说我们还可以自订变量吗?因此,除了 env 这个读取环境变量的指令之外,还有一个可以将目前系统中所有的变量数据都读出来的指令,称为 set !set 除了会将上面的数据都给他读出来之外,还会有额外的这些信息也一起读入(通常都与使用者的设定有关!)
- set
显示目前系统中全部的变量内容
语法: set 的输入就是直接输入 set 即可!他除了会显示出目前的『环境变量』之外,也会显示出您的『自订变量』呢!那么有哪些与使用者较有相关性的自订变量呢?我们上面仅列出部分常见的变量值啰!
使用 set 除了会将系统的默认值秀出来之外,连带的所有的你自己设定的变量也会被秀出来!同时需要注意的是,若当时有相当多人同时在在线的话,那么你的变量只能给自己使用(除非改的是系统的预设参数档,如 /etc/profile ),而不会干扰到别人的!就如同前面所说的,由于你登入 Linux 之后会取得一个 PID ,而你的设定将只对这个 PID 与子程序有关!此外,这次登入所进行的变量设定,如果没有更动到设定档,那么这次设定的变量在下次登入时将被取消掉(因为程序 PID 不见啰!)!所以啰,如果你想要你的变量每次都能在你登入的时候自动就设定好了,那么就必须将你的设定写入登入时加载的设定档!
上面的变量中,比较有趣的是 $ 与 ? 这两个咚咚,尤其是 ? 这个变量,如果您上一个命令执行的过程中没有错误,那么这个变量就会被设定为 0 ,如果您的上个命令有错误讯息,那么这个变量会变成 1 或其它的错误代码!现在马上动手试看看您的上个指令执行成果为何?
echo $?
- 变量设定规则:
好了,我们知道了一些系统的预设变量了,但是如果是我自己想要设定一些我自己的变量,该如何设定呢?有什么规则需要遵守?呵呵!在说明之前,可能要来让大家了解一下为什么自己会想来设定变量?
- 我的案例一:最简单的例子就是『路径名称』啰!以鸟哥为例,我的工作在 Unix 系统之下进行一些数值模式的仿真工作,偏偏由于数据量太大,为了怕日后忘记这个目录的内容与主要的意义,所以我的档名都取的很长,偏偏在执行模式的过程中,常常会切换目录!我哩ㄌㄟ,光是打那几行路径名称就快要疯掉了!所以我就设定那几行目录名称成为一个四个字符的变量,如此一来我只要输入『 cd $VARI 』这个指令,嘿嘿!马上就移动到该路径下了!很方便吧!当然变量的意义还不止于此,不过这是最简单的实例说明啰!
- 或者是使用于 scripts 的意义,我们必须要设定变量!然而在 bash 底下的变量设定是有一定规则的,必须要来遵守才行:
- 变量与变量内容以等号『=』来连结;
- 等号两边不能直接接空格符;
- 变量名称只能是英文字母与数字,但是数字不能是开头字符;
- 若有空格符可以使用双引号『 " 』或单引号『 ' 』来将变量内容结合起来,但须要特别留意,双引号内的特殊字符可以保有变量特性,但是单引号内的特殊字符则仅为一般字符;
- 必要时需要以跳脱字符『 \ 』来将特殊符号(如Enter, $, \, 空格符, '等)变成一般符号;
- 在一串指令中,还需要藉由其它的指令提供的信息,可以使用 quote 『 ` command` 』;
- 若该变量为扩增变量内容时,则需以双引号及 $变量名称如:『 "$PATH":/home』继续累加内容;
- 若该变量需要在其它子程序执行,则需要以 export 来使变量可以动作,如『export PATH』;
- 通常大写字符为系统预设变量,自行设定变量可以使用小写字符,方便判断(纯粹依照使用者兴趣与嗜好);
- 取消变量的方法为:『unset 变量名称』。
底下我们举几个例子来说明一下:
一般变量设定: [tets @test test]# 12name=VBrid <==错误的!因为变量开头不能是数字! [test @test test]# name = VBird <==错误的!因为等号两边不能直接接空白! [test @test test]# name=VBird <==正确的!echo $name 显示 VBird [test @test test]# name=VBird name <==错误的!需要加上双引号!不然会显示错误! [test @test test]# name="VBird name" <==正确的!echo $name 显示 VBird name [test @test test]# name="VBird's name" <==正确的! 变量累加设定: [test @test test]# name=$nameisme <==错误的!需要以双引号将原变量圈起来 [test @test test]# name="$name"isme <==正确的!echo $name 显示 VBird's nameisme [test @test test]# PATH="$PATH":/home/test <==正确的!echo $PATH 将多了后面一句话! [test @test test]# PATH="$PATH:/home/test" <==正确的!这个形式对于 PATH 来说也是正确的格式! 变量延伸到下一个子程序: [test @test test]# name="VBird's name" <==设定 name 这个变量 [test @tset test]# echo $name <==显示 name 变量的指令 [test @test test]# VBird's name [test @test test]# /bin/bash <==另开一个 bash 的子程序 [test @tset test]# echo $name <==显示 name 这个变量 [test @tset test]# <==会显示空字符串因为 name 这个变量不能使用在子程序 [test @test test]# exit <==退出子程序 bash shell ! [test @test test]# export name <==正确的!如此则 $name 可以用于下一个子程序中! 指令中的指令: [test @test test]# cd /lib/modules/`uname –r`/kernel 上式中,会先执行 `uname –r` 这个内含指令,然后输出的结果附加在 /lib/module… 里面,所以执行这个指令,可以完成几个附指令程序! 取消变量设定: [test @test test]# unset name |
根据上面的案例你可以试试看!就可以了解变量的设定啰!这个是很重要的呦!请勤加练习!!其中,较为重要的一些特殊符号的使用啰!例如单引号、双引号、跳脱字符、钱字号、quote 符号等等,底下的例题想一想吧!
例题:在变量的设定中,单引号与双引号有什么不同呢? 答: 单引号与双引号的最大不同在于双引号仍然可以保有变量的内容,但单引号内仅能是一般字符,而不会有特殊符号。我们以底下的例子做说明:假设您定义了一个变量, name=VBird ,现在想以 name 这个变量定义出 myname 显示 VBird its me 这个内容,要如何订定呢?[root @test root]# name=VBird发现了吗?没错!使用了单引号的时候,那么 $name 将失去原有的变量内容,仅为一般字符的显示型态而已!这里必需要特别小心在意! |
例题:在指令下达的过程中, quote ( ` ) 这个符号代表的意义为何? 答: 在一串指令中,在 ` 之内的指令将会被先执行,而其执行出来的结果将做为外部的输入信息!例如 uname –r 会显示出目前的核心版本,而我们的核心版本在 /lib/modules 里面,因此,你可以先执行 uname –r 找出核心版本,然后再以『 cd 目录』到该目录下,当然也可以执行cd /lib/modules/`uname –r`直接到该目录下去! |
底下我们来谈一谈 export 的用途吧!
- export
当你取得一个 bash 之后,亦即得到了一个程序了,但是若你再次的执行一次 bash ,那么你将进入『子程序』,这个程序的概念我们在资源管理章节中再详谈,这里您先有个概念即可。那么由于您已经进入了该子程序,所以在父程序中的变量设定将不再继续的存在。如您想要让该变量内容继续的在子程序中使用,那么就请执行:
export 变数
!这个东西用在『引用他人的档案或者其它程序』时,相当的重要的!尤其像我常常两三个档案互相引用来引用去的,如果忘记设定 export 的话,那么不同的档案中的相同变量值,将需要一再地重复设定才行!所以,我只要在头一个档案使用 export 的话,那么后续的档案引用时,将会把该变量内容读进来!好用的很?而,如果仅下达 export 而没有接变量时,那么此时将会把所有的『环境变量』秀出来喔!也就是说, export 可以将一般自订的变量变成环境变量!
- unset
就是直接将该变量的内容拿掉:
unset 变数
- 变量的有效范围:
由前面的 export 以及相关的说明,你可以很清楚的知道一件事情,那就是,『变量的设定只在目前这个 shell 环境当中存在,在下个或者是在子程序中 ( 子 shell ) 将不会存在!』要让变量在下个程序也可以继续的使用,大概就是使用 export 这个咚咚啦!此外,其实除了 shell 的父、子程序外,在脚本( scripts )的编写当中,由于有的软件会使用到 2 个以上的 scripts 做为一个完整的套件!也就是说,假如你有两支程序,一支为 scripts1.sh 以及 scripts2.sh ,而 scripts2.sh 会去引用 scripts1.sh 的变数,这个时候,嘿嘿!你在 scripts1.sh 当中设定的变量请『千万记得以 export 设定』,否则你的变量将无法在两个 scripts 之间互相被引用喔!当这个 scripts 执行完毕之后,刚刚在 scripts 当中设定的变量也就『失效了!』。
- 其它的注意事项:
乍看之下变量似乎没有什么值得我们来留意的地方,其实不然,变量可以让我们的系统管理变的更加的简单,举个例子来说,刚刚我们提到 HISTSIZE 可以控制历史指令的多寡,那么太多的话,可能会有安全的顾虑之虞,那么是否需要改小一点呢?当然需要~此外,关于路径的设定方面,当您使用一般身份使用者登入系统,再以 su 转换成 root 身份时,基本上,一堆环境变量仍是以当初的一般身份者为主的,因此,您常常会发现 root 使用的指令会『找不到!』那就是环境变量的错误设定啦!这个时候,如果您能够将该一般身份使用者的路径设定成为 root 能用的指令的样子,嗯!那么转换身份的时候,将可以免除相当多的困扰呢!提供给你做为参考了!
- read:
上面我们谈到的『变量』都是由『指令列』直接设定好的!那么可不可以随时来提供使用只以键盘随时输入变量内容?也就是说,变量内容是由使用者由键盘输入的哩!呵呵!可以使用 read 来达成喔!这个东西在『 script 』里面比较重要啦!所以我们在 shell script 里面会再次的提到喔!
语法:
[test @test test]# read name
testing <==这个时候屏幕会等待使用者由键盘输入喔!
[test @test test]# echo $name
testing <==刚刚输入的数据变成了变量的内容啦!- $RANDOM:
有听过『随机取随机数』这个玩意儿吧!?呵呵!那么在 BASH 里面的随机数是那个变数来的?随机数在英文的写法为 RANDOM 啦,所以啰, BASH 当中针对随机数的变量名称就是 $RANDOM 啰!来给他秀一下吧!
语法:
[test @test test]# echo $RANDOM
xxxx <==每次都会出现不同的数字喔!随机数对于程序设计师比较重要,对于我们一般使用者,重要性就没有这么大啦!只是提出来让大家知道一下就是了!
- 命令别名:
命令别名是一个很有趣的东西,特别是你的惯用指令特别长的时候!还有,增设预设的属性在一些惯用的指令上面,可以预防一些不小心误杀档案的情况发生的时候!举个例子来说,如果你要查询隐藏档,并且需要长的列出与一页一页翻看,那么需要下达『 ls -al | more 』这个指令,我是觉得很烦啦!要输入好几个单字!那可不可以使用 lm 来简化呢?!当然可以,你可以在命令列下面下达:[test @tset test]# alias lm='ls -al | more' 要注意的是:『alias 的定义规则与变量定义规则几乎相同』,所以你只要在 alias 后面加上你的{『别名』='指令 参数'},以后你只要输入 lm 就相当于输入了 ls -al|more 这一串指令!很方便吧!另外,我们知道 root 可以移除( rm )任何数据!所以当你以 root 的身份在进行工作时,需要特别小心,但是总有失手的时候,那么 rm 提供了一个参数来让我们确认是否要移除该档案,那就是 -i 这个参数!所以,你可以这样做:
[test @tset test]# alias rm='rm -i'
嘿嘿!那么以后使用 rm 的时候,就不用太担心会有错误删除的情况了!这也是命令别名的优点啰!那么如何知道目前有哪些的命令别名呢?就使用 alias 呀![test @tset test]# alias
alias l.='ls -d .[a-zA-Z]* --color=tty'
alias ll='ls -l'
alias lm='ls -al'
alias ls='ls --color=tty'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'至于如果要取消命令别名的话,那么就使用 unalias 吧!
那么命令别名与变量有什么不同呢?基本上,他们的意义就不太一样了! alias 这种命令别名,你可以将他想成是建立一个新的指令名称,至于变量则仅是将一个数值或者字符串存在某个代表意义当中!举个例子好了,我们知道以前的 DOS 年代,列出目录与档案就是 dir ,而清除屏幕就是 cls ,那么如果我想要在 linux 里面也使用相同的指令呢?那就以 alias 来进行指令的别名设定:
- alias cls=’clear’
alias dir=’ls –l’
只要加入这两行,以后你输入 cls 及 dir 就可以执行了!很方便吧!
- 历史指令记录数据:
前面我们提过 bash 有提供指令历史的服务!那么如何查询我们曾经下达过的指令呢?就使用 history 啰!当然,如果觉得 histsory 太麻烦,可以使用命令别名来设定呢!不要跟我说还不会设定呦!
- alias h=’history’
如此则输入 h 等于输入 history 啰!好了,我们来谈一谈 history 的用法吧!
- history, !command
显示历史指令记录内容, 下达历史纪录中的指令
语法:
说明:[test @test test]# history
[test @test test]# [!number] [!command] [!!]
参数说明:
number :第几个指令的意思;
command :指令的开头几个字母
! :上一个指令的意思!
范例:
[test @test test]# history <==底下列出的就是(1)历史指令的编号;(2)指令的内容
66 man rm
67 alias
68 man history
69 history
[test @test test]# !66 <==执行第 66 个历史指令
[test @test test]# !! <==执行上一个指令(在本例中,就是 !66 那一个指令!)
[test @test test]# !al <==执行最近一次以 al 为开头的指令内容,就是第 67 个指令啰!
history 这个指令配合 ! 这个用法就多了!如果我想要执行上一个指令,除了使用上下键之外,我可以直接以 !! 来下达上个指令的内容,此外,我也可以直接选择下达第 n 个指令, !n 来执行,也可以使用指令标头,例如 !vi 来执行最近指令开头是 vi 的指令列!相当的方便而好用!基本上 history 的用途很大的!但是需要小心安全的问题!尤其是 root 的历史纪录档案,这是 Cracker 的最爱!因为不小心的 root 会将很多的重要数据在执行的过程中会被纪录在 ~/.bash_history 当中,如果这个档案被解析的话,后果不堪吶!无论如何,使用 history 配合『 ! 』曾经使用过的指令下达是很有效率的一个指令方法!