概要:

         shell中,变量有环境变量和自定义变量之分,环境 变量相当于全局变量,自定义变量相当于局部变量,因此父程序的环境变量变量会被子程序所引用,而自定义变量则不可以。其中的原因在于子程序仅会继承父程序的环境变量, 子程序不会继承父程序的自定义变量。

 
  
  1. 为什么环境变量的数据可以被子程序所引用呢?这是因为内存配置的关系!理论上是这样的: 
  2.  
  3. 当启动一个 shell,操作系统会分配一记忆区块给 shell 使用,此内存内之变量可让子程序取用 
  4. 若在父程序利用 export 功能,可以让自定义变量的内容写到上述的记忆区块当中(环境变量); 
  5. 当加载另一个 shell 时 (亦即启动子程序,而离开原本的父程序了),子 shell 可以将父 shell 的环境变量所在的记忆区块导入自己的环境变量区块当中。 
 
  
  1. 本文目录索引: 
  2. 1、变量的显示 
  3.                   echo --显示变量内容 
  4.                   unset --取消变量 
  5.                   env --观察环境变量 
  6.                   set --观察环境变量与自定义变量 
  7.                  export --自定义变量转成环境变量 
  8.                  declare / typeset --宣告变量的类型(也可以将环境变量转成自定义变量) 
  9. 2、变量的读取 
  10.                  read --读取来自键盘输入的变量 
  11. 3、通配符与特殊符号 
  12. 4、变量的配置守则 
  13. 5、变量内容的删除、取代与测试、替换 
  14.                变量内容的删除与取代 删除 取代
  15. 变量的测试与内容替换 

变量的显示


 echo --显示变量内容
 
  
  1. 格式:echo $variable  
  2.           echo ${variable}  
 
  
  1.  echo $PATH 
  2. /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin 
  3. [root@www ~]# echo ${PATH} 
  4. /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin 

 unset --取消变量
 
  
  1. 格式:unset 变量名称 
 
  
  1. 取消 myname 的配置:  
  2. [root@www ~]#unset myname  

 env --观察环境变量
 
  
  1. 范例一:列出目前的 shell 环境下的所有环境变量与其内容。 
  2. [root@www ~]# env 
  3. HOSTNAME=www.vbird.tsai    <== 这部主机的主机名 
  4. TERM=xterm                 <== 这个终端机使用的环境是什么类型 
  5. SHELL=/bin/bash            <== 目前这个环境下,使用的 Shell 是哪一个程序? 
  6. HISTSIZE=1000              <== 『记录命令的笔数』在 CentOS 默认可记录 1000 笔 
  7. USER=root                  <== 使用者的名称啊! 
  8. 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: 
  9. or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=0 
  10. 0;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz= 
  11. 00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;3 
  12. 1:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00 
  13. ;35:*.xpm=00;35:*.png=00;35:*.tif=00;35: <== 一些颜色显示 
  14. MAIL=/var/spool/mail/root  <== 这个用户所取用的 mailbox 位置 
  15. PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin: 
  16. /root/bin                  <== 不再多讲啊!是运行文件命令搜寻路径 
  17. INPUTRC=/etc/inputrc       <== 与键盘按键功能有关。可以配置特殊按键! 
  18. PWD=/root                  <== 目前用户所在的工作目录 (利用 pwd 取出!) 
  19. LANG=en_US                 <== 这个与语系有关,底下会再介绍! 
  20. HOME=/root                 <== 这个用户的家目录啊! 
  21. _=/bin/env                 <== 上一次使用的命令的最后一个参数(或命令本身) 

部分环境变量的介绍如下:

 
  
  1. HOME 
  2. 代表用户的家目录。还记得我们可以使用 cd ~ 去到自己的家目录吗?或者利用 cd 就可以直接回到用户家目录了。那就是取用这个变量啦~ 有很多程序都可能会取用到这个变量的值! 
  3.  
  4. SHELL 
  5. 告知我们,目前这个环境使用的 SHELL 是哪支程序? Linux 默认使用 /bin/bash 的啦! 
  6.  
  7. HISTSIZE 
  8. 这个与『历史命令』有关,亦即是, 我们曾经下达过的命令可以被系统记录下来,而记录的『笔数』则是由这个值来配置的。 
  9.  
  10. MAIL 
  11. 当我们使用 mail 这个命令在收信时,系统会去读取的邮件信箱文件 (mailbox)。 
  12.  
  13. PATH 
  14. 就是运行文件搜寻的路径啦~目录与目录中间以冒号(:)分隔, 由于文件的搜寻是依序由 PATH 的变量内的目录来查询,所以,目录的顺序也是重要的喔。 
  15.  
  16. LANG 
  17. 这个重要!就是语系数据啰~很多信息都会用到他, 举例来说,当我们在启动某些 perl 的程序语言文件时,他会主动的去分析语系数据文件, 如果发现有他无法解析的编码语系,可能会产生错误喔!一般来说,我们中文编码通常是 zh_TW.Big5 或者是 zh_TW.UTF-8,这两个编码偏偏不容易被解译出来,所以,有的时候,可能需要修订一下语系数据。 这部分我们会在下个小节做介绍的! 
  18.  
  19. RANDOM 
  20. 这个玩意儿就是『随机随机数』的变量啦!目前大多数的 distributions 都会有随机数生成器,那就是 /dev/random 这个文件。 我们可以透过这个随机数文件相关的变量 ($RANDOM) 来随机取得随机数值喔。在 BASH 的环境下,这个 RANDOM 变量的内容,介于 0~32767 之间,所以,你只要 echo $RANDOM 时,系统就会主动的随机取出一个介于 0~32767 的数值。万一我想要使用 0~9 之间的数值呢?呵呵~利用 declare 宣告数值类型, 然后这样做就可以了: 
  21. [root@www ~]# declare -i number=$RANDOM*10/32768  
  22. [root@www ~]#  echo $number 
  23. 8   <== 此时会随机取出 0~9 之间的数值喔! 
 

 set --观察环境变量与自定义变量
 
  
  1. 一般来说,不论是否为环境变量,只要跟我们目前这个 shell 的操作接口有关的变量, 通常都会被配置为大写字符,也就是说,『基本上,在 Linux 默认的情况中,使用{大写的字母}来配置的变量一般为系统内定需要的变量』。 OK!OK!那么上头那些变量当中,有哪些是比较重要的?大概有这几个吧! 
  2.  
  3.  
  4.  
  5. PS1:(提示字符的配置) 
  6.  
  7. 这是 PS1 (数字的 1 不是英文字母),这个东西就是我们的『命令提示字符』喔! 当我们每次按下 [Enter] 按键去运行某个命令后,最后要再次出现提示字符时, 就会主动去读取这个变量值了。上头 PS1 内显示的是一些特殊符号,这些特殊符号可以显示不同的信息, 每个 distributions 的 bash 默认的 PS1 变量内容可能有些许的差异,不要紧,『习惯你自己的习惯』就好了。 你可以用 man bash (注3)去查询一下 PS1 的相关说明,以理解底下的一些符号意义。 
  8.  
  9. \d :可显示出『星期 月 日』的日期格式,如:"Mon Feb 2" 
  10. \H :完整的主机名。举例来说,鸟哥的练习机为『www.vbird.tsai』 
  11. \h :仅取主机名在第一个小数点之前的名字,如鸟哥主机则为『www』后面省略 
  12. \t :显示时间,为 24 小时格式的『HH:MM:SS』 
  13. \T :显示时间,为 12 小时格式的『HH:MM:SS』 
  14. \A :显示时间,为 24 小时格式的『HH:MM』 
  15. \@ :显示时间,为 12 小时格式的『am/pm』样式 
  16. \u :目前使用者的账号名称,如『root』; 
  17. \v :BASH 的版本信息,如鸟哥的测试主板本为 3.2.25(1),仅取『3.2』显示 
  18. \w :完整的工作目录名称,由根目录写起的目录名称。但家目录会以 ~ 取代; 
  19. \W :利用 basename 函数取得工作目录名称,所以仅会列出最后一个目录名。 
  20. \# :下达的第几个命令。 
  21. \$ :提示字符,如果是 root 时,提示字符为 # ,否则就是 $ 啰~ 
  22.  
  23. 好了,让我们来看看 CentOS 默认的 PS1 内容吧:『[\u@\h \W]\$ 』,现在你知道那些反斜杠后的数据意义了吧? 要注意喔!那个反斜杠后的数据为 PS1 的特殊功能,与 bash 的变量配置没关系啦!不要搞混了喔! 那你现在知道为何你的命令提示字符是:『 [root@www ~]# 』了吧? 好了,那么假设我想要有类似底下的提示字符: 
  24. [root@www /home/dmtsai 16:50 #12]# 
  25. 那个 # 代表第 12 次下达的命令。那么应该如何配置 PS1 呢?可以这样啊: 
  26. [root@www ~ ]# cd /home 
  27. [root@www home]# PS1='[\u@\h \w \A #\#]\$ ' 
  28. [root@www /home 17:02 #85]#  
  29. # 看到了吗?提示字符变了!变的很有趣吧!其中,那个 #85 比较有趣, 
  30. # 如果您再随便输入几次 ls 后,该数字就会添加喔!为啥?上面有说明滴! 
  31.  
  32.  
  33.  
  34. $:(关于本 shell 的 PID) 
  35.  
  36. 钱字号本身也是个变量喔!这个咚咚代表的是『目前这个 Shell 的线程代号』,亦即是所谓的 PID (Process ID)。 更多的程序观念,我们会在第四篇的时候提及。想要知道我们的 shell 的 PID ,就可以用:『 echo $$ 』即可!出现的数字就是你的 PID 号码。 
  37.  
  38.  
  39.  
  40. ?:(关于上个运行命令的回传值) 
  41.  
  42. 什么?问号也是一个特殊的变量?没错!在 bash 里面这个变量可重要的很! 这个变量是:『上一个运行的命令所回传的值』, 上面这句话的重点是『上一个命令』与『回传值』两个地方。当我们运行某些命令时, 这些命令都会回传一个运行后的代码。一般来说,如果成功的运行该命令, 则会回传一个 0 值,如果运行过程发生错误,就会回传『错误代码』才对!一般就是以非为 0 的数值来取代。 我们以底下的例子来看看: 
  43. [root@www ~]# echo $SHELL 
  44. /bin/bash                                  <==可顺利显示!没有错误! 
  45. [root@www ~]# echo $? 
  46. 0                                          <==因为没问题,所以回传值为 0 
  47. [root@www ~]# 12name=VBird 
  48. -bash: 12name=VBird: command not found     <==发生错误了!bash回报有问题 
  49. [root@www ~]# echo $? 
  50. 127                                        <==因为有问题,回传错误代码(非为0) 
  51. # 错误代码回传值依据软件而有不同,我们可以利用这个代码来搜寻错误的原因喔! 
  52. [root@www ~]# echo $? 
  53. # 咦!怎么又变成正确了?这是因为 "?" 只与『上一个运行命令』有关, 
  54. # 所以,我们上一个命令是运行『 echo $? 』,当然没有错误,所以是 0 没错! 
  55.  
  56.  
  57.  
  58. OSTYPE, HOSTTYPE, MACHTYPE:(主机硬件与核心的等级) 
  59.  
  60. 我们在第零章、计算器概论内的 CPU 等级说明中谈过 CPU , 目前个人计算机的 CPU 主要分为 32/64 位,其中 32 位又可分为 i386, i586, i686,而 64 位则称为 x86_64。 由于不同等级的 CPU 命令集不太相同,因此你的软件可能会针对某些 CPU 进行优化,以求取较佳的软件性能。 所以软件就有 i386, i686 及 x86_64 之分。以目前 (2009) 的主流硬件来说,几乎都是 x86_64 的天下! 但是毕竟旧机器还是非常多,以鸟哥的环境来说,我用 P-III 等级的计算机,所以上头就发现我的等级是 i686 啦! 
  61.  
  62. 要留意的是,较高阶的硬件通常会向下兼容旧有的软件,但较高阶的软件可能无法在旧机器上面安装! 我们在第三章就曾说明过, 这里再强调一次,你可以在 x86_64 的硬件上安装 i386 的 Linux 操作系统,但是你无法在 i686 的硬件上安装 x86_64 的 Linux 操作系统!这点得要牢记在心! 
 
 export --自定义变量转成环境变量

 export可以将自定义变量变成环境变量,让该变量值继续存在于子程序,让该变量内容继续的在子程序中使用。

 
  
  1. 格式:export 变量名称 

如果仅下达 export 而没有接变量时,那么此时将会把所有的『环境变量』显示出来!例如:

 
  
  1. [root@www ~]# export 
  2. declare -x HISTSIZE="1000" 
  3. declare -x HOME="/root" 
  4. declare -x HOSTNAME="www.vbird.tsai" 
  5. declare -x INPUTRC="/etc/inputrc" 
  6. declare -x LANG="en_US" 
  7. declare -x LOGNAME="root" 
  declare / typeset --宣告变量的类型(也可以将环境变量转成自定义变量)

 declare 语法如下:

如果你不小心将变量配置为『只读』,通常得要注销再登陆才能复原该变量的类型了!

在默认的情况底下, bash 对于变量有几个基本的定义:

 
  
  1. 变量类型默认为『字符串』,所以若不指定变量类型,则 1+2 为一个『字符串』而不是『计算式』。 所以上述第一个运行的结果才会出现那个情况的; 
  2. bash 环境中的数值运算,默认最多仅能到达整数形态,所以 1/3 结果是 0; 

变量的读取


 read --读取来自键盘输入的变量

 通配符与特殊符号


 

 变量的配置守则


 
  
  1. 1.变量名称只能是英文字母与数字,但是开头字符不能是数字,如下为错误:   
  2. 『2myname=VBird』  
  3.   
  4. 2.等号两边不能直接接空格符,如下所示为错误:   
  5. 『myname = VBird』或『myname=VBird Tsai』  
  6.   
  7. 3.变量内容若有空格符可使用双引号『"』或单引号『'』将变量内容结合起来,但  
  8. 双引号内的特殊字符如 $ 等,可以保有原本的特性,如下所示:  
  9. 『var="lang is $LANG"』则『echo $var』可得『lang is en_US』  
  10. 单引号内的特殊字符则仅为一般字符 (纯文本),如下所示:  
  11. 『var='lang is $LANG'』则『echo $var』可得『lang is $LANG』  
  12.   
  13. 4.在一串命令中,还需要藉由其他的命令提供的信息,可以使用反单引号『`命令`』或 『$(命令)』。特别注意,那个 ` 是键盘上方的数字键 1 左边那个按键,而不是单引号! 例如想要取得核心版本的配置:  
  14. 『version=$(uname -r)』再『echo $version』可得『2.6.18-128.el5』  
  15.   
  16. 5.可用跳脱字符『 \ 』将特殊符号(如 [Enter], $, \, 空格符, '等)变成一般字符;  
  17.   
  18. 6.若该变量为扩增变量内容时,则可用 "$变量名称" 或 ${变量} 累加内容,如下所示:  
  19. 『PATH="$PATH":/home/bin』  
  20.   
  21. 7.通常大写字符为系统默认变量,自行配置变量可以使用小写字符,方便判断 (纯粹依照使用者兴趣与嗜好) ;  
  22.   
  23. 8.若该变量需要在其他子程序运行,则需要以 export 来使变量变成环境变量:  
  24. 『export PATH』  

举例如下:

根据上面的案例你可以试试看!就可以了解变量的配置啰!这个是很重要的呦!请勤加练习! 其中,较为重要的一些特殊符号的使用啰!例如单引号、双引号、跳脱字符、钱字号、反单引号等等,底下的例题想一想吧!例题:

例题:
在变量的配置当中,单引号与双引号的用途有何不同?
答:
单引号与双引号的最大不同在于 双引号仍然可以保有变量的内容,但单引号内仅能是一般字符 ,而不会有特殊符号。我们以底下的例子做说明:假设您定义了一个变量, name=VBird ,现在想以 name 这个变量的内容定义出 myname 显示 VBird its me 这个内容,要如何订定呢?
[root@www ~]# name=VBird
[root@www ~]# echo $name
VBird
[root@www ~]# myname="$name its me"
[root@www ~]# echo $myname
VBird its me
[root@www ~]# myname='$name its me'
[root@www ~]# echo $myname
$name its me
发现了吗?没错!使用了单引号的时候,那么 $name 将失去原有的变量内容,仅为一般字符的显示型态而已!这里必需要特别小心在意!

例题:
在命令下达的过程中,反单引号( ` )这个符号代表的意义为何?
答:
在一串命令中,在 ` 之内的命令将会被先运行,而其运行出来的结果将做为外部的输入信息!例如 uname -r 会显示出目前的核心版本,而我们的核心版本在 /lib/modules 里面,因此,你可以先运行 uname -r 找出核心版本,然后再以『 cd 目录』到该目录下,当然也可以运行如同上面范例六的运行内容啰。 

另外再举个例子,我们也知道,  locate 命令可以列出所有的相关文件档名,但是,如果我想要知道各个文件的权限呢?举例来说,我想要知道每个 crontab 相关档名的权限:
[root@www ~]# ls -l `locate crontab`
如此一来,先以 locate 将文件名数据都列出来,再以 ls 命令来处理的意思啦!瞭了吗? ^_^

例题:
若你有一个常去的工作目录名称为:『/cluster/server/work/taiwan_2005/003/』,如何进行该目录的简化?
答:
在一般的情况下,如果你想要进入上述的目录得要『cd /cluster/server/work/taiwan_2005/003/』, 以鸟哥自己的案例来说,鸟哥跑数值模式常常会配置很长的目录名称(避免忘记),但如此一来变换目录就很麻烦。 此时,鸟哥习惯利用底下的方式来降低命令下达错误的问题:
[root@www ~]# work="/cluster/server/work/taiwan_2005/003/"
[root@www ~]# cd $work
未来我想要使用其他目录作为我的模式工作目录时,只要变更 work 这个变量即可!而这个变量又可以在 bash 的配置文件中直接指定,那我每次登陆只要运行『 cd $work 』就能够去到数值模式仿真的工作目录了!是否很方便呢? ^_^

Tips:
老实说,使用『 version=$(uname -r) 』来取代『 version=`uname -r` 』比较好,因为反单引号大家老是容易打错或看错! 所以现在鸟哥都习惯使用 $( 命令 ) 来介绍这个功能!

 变量内容的删除、取代与测试、替换


 变量内容的删除与取代

1、删除:

 
  
  1. # :符合取代文字的『最短的』那一个; 
  2. ##:符合取代文字的『最长的』那一个 ;

eg:『从前面开始删除变量内容』

eg:『从后面向前删除变量内容』

 

由于我是想要由变量内容的后面向前面删除,而我这个变量内容最后面的结尾是『/root/bin』, 所以你可以看到上面我删除的数据最终一定是『bin』,亦即是『:*bin』那个 * 代表通配符! 至于 % 与 %% 的意义其实与 # 及 ## 类似!这样理解否?

例题:
假设你是 root ,那你的 MAIL 变量应该是 /var/spool/mail/root 。假设你只想要保留最后面那个档名 (root), 前面的目录名称都不要了,如何利用 $MAIL 变量来达成?
答:

题意其实是这样『/var/spool/mail/root』,亦即删除掉两条斜线间的所有数据(最长符合)。 这个时候你就可以这样做即可:

 
       
  1. [root@www ~]# echo ${MAIL##/*/} 

相反的,如果你只想要拿掉文件名,保留目录的名称,亦即是『/var/spool/mail/root』 (最短符合)。但假设你并不知道结尾的字母为何,此时你可以利用通配符来处理即可,如下所示:

 
       
  1. [root@www ~]# echo ${MAIL%/*} 

 

2、取代:

 变量的测试与内容替换

 在某些时刻我们常常需要『判断』某个变量是否存在,若变量存在则使用既有的配置,若变量不存在则给予一个常用的配置。

不过这还是有点问题!因为 username 可能已经被配置为『空字符串』了!果真如此的话,那你还可以使用底下的范例来给予 username 的内容成为 root 喔!

在大括号内有没有冒号『 : 』的差别是很大的!加上冒号后,被测试的变量未被配置或者是已被配置为空字符串时, 都能够用后面的内容 (本例中是使用 root 为内容) 来替换与配置!

如果你想要将旧变量内容也一起替换掉的话,那么就使用等号 (=) 吧!

那如果我只是想知道,如果旧变量不存在时,整个测试就告知我『有错误』,此时就能够使用问号『 ? 』的帮忙啦!

 文章出自:http://vbird.dic.ksu.edu.tw/linux_basic/0320bash_2.php#variable_other_re《鸟哥的linux私房菜》,请尊重原作者的劳动成果!