现在的位置: 首页 > 综合 > 正文

shell环境变量

2013年01月29日 ⁄ 综合 ⁄ 共 7213字 ⁄ 字号 评论关闭

shell环境变量  

环境变量 
还记得上一章里面﹐我曾经提到过﹕当我们登入系统的时候﹐首先就获得一 shell﹐而且它也占据一个行程(进程)﹐然后再输入的命令都属于这个 shell 的子程序(子进程)。如果您学习够细心﹐不难发现我们的 shell 都在 /etc/passwd 这个档里面设定的﹐也就是账号设定的最后一栏﹐预设是 /bin/bash 。 
事实上﹐当我们获得一个 shell 之后﹐我们才真正能和系统沟通﹐例如输入您的命令﹑执行您的程序﹑等等。您也可以在获得一个 shell 之后﹐再进入另外一个 shell (也就是启动一个子程序)﹐然后还可以再进入更深一层的 shell (再进入子程序的子程序)﹐直到您输入 exit 才退回到上一个 shell 里面(退回上一级的父程序)。假如您已经阅读过上一章所说过的子程序概念﹐应该不难理解。不过﹐您的行为也不是无限制的﹐而且﹐有许多设定都必须事先得到 定义。所以﹐当您获得 shell 的时候﹐同时也获得一些环境设定﹐或称为“环境变量( Environmentvariables)”。 
所谓的 变量( variable )﹐ 就是用特定的名称(或标签)保存一定的设定值﹐然后供程序将来使用。例如﹐姓=chen ﹔名=kenny ﹐那么‘姓’和‘名’就是变量名称﹐而 chen 和 kenny 就是变量所保存的值。由 shell 所定义和管理的变量﹐我们称为环境变量﹐因为这些变量可以供 shell 所产生的所有子程序使用。环境变量名称一般都用大写字母表示﹐例如﹐我们常用的环境变量有这些﹕ 
(注:也就是说环境变量,就是供shell所产生的所有子进程使用的变量)
变量名称
代表意思
HISTCMD
当前命令的记录编号。
HISTFILE
命令记录表之存放档案。
HISTSIZE
命令记录表体积。
HOME
默认登录家目录。
IFS
预设分隔符。
LINENO
当前命令在 shell script 中的行数。
MAIL
邮件信箱的路径。
MAILCHECK
检查邮件的秒数。
OLDPWD
上次进入的目录路径。
OSTYPE
操作系统类型。
PATH
默认命令搜索路径。
PPID
父程序之 PID。
PWD
当前工作目录路径。
SECONDS
当前 shell 之持续启动时间。
SHELL
当前 shell 之执行路径。
TMOUT
自动注销之最高闲置时间。
UID
使用者之 UID。
$
当前 shell 之 PID。

最后一个命令之返回状态。
假如您想看看这些变量值是什么﹐只要在变量名称前面加上一个“$”符号﹐然后用 echo 命令来查看就可以了﹕ 
echo$PWD 
/root 
echo $$ 
1206 
echo $? 

第一个命令就是将当前目录的路径显示出来﹐和您执行 pwd 命令的结果是一样的﹔第二个命令将当前这个 shell 的 PID 显示出来﹐也就是 1206。如果您这时候输入 kill -9 1206 的话﹐会将当前的 shell 砍掉﹐那您就要重新登录才能获得另外一个 shell﹐而它的 PID 也是新的﹔第三行命令是上一个命令的返回状态﹕如果命令顺利执行﹐并没有错误﹐那通常是 0﹔如果命令遇到错误﹐那返回状态则是非 0 ﹐其值视程序设计者而定(我们在后面的 shell script 的时候会介绍)。关于最后一个命令﹐不妨比较一下如下结果﹕ 
ls mbox 
mbox 
echo $? 

ls no_mbox 
ls: no_mbox: No such file or directory 
echo $? 

您会发现﹕第一命令成功执行﹐所以其返回状态是 0 ﹔而第二个命令执行失败﹐其返回状态是 1 。假如程序设计者为不同的错误设定不同的返回状态等级﹐那您可以根据返回值推算出问题是哪种错误引起的。 
Tips﹕如果您日后写程序或 script﹐要养成一个习惯﹐为每一种命令结果设定返回状态。这非常重要﹐尤其在进行 debug 的时候。这个我们在后面学习 script 的时候再谈。 (这点很重要要引起重视!)
我们随时都可以用一个 = (等号) 来定义一个新的变量或改变一个原有变量。例如﹕ 
MYNAME=kenny 
echo $MYNAME 
kenny 
假如您要取消一个定义好的变量﹐那么﹐您可以使用 unset 命令﹕ 
unset MYNAME 
不过﹐环境变量的特性之一﹐是单向输出的。也就是说﹕一个 shell 的特定变量﹐只能在这个 shell 里面使用。如果您要分享给同一个 shell 里面的其它程序﹑script﹑命令使用﹐或它们的子程序使用﹐那您必须用 export 命令将这个变量进行输出。但无论如何﹐如果您在一个子程序中定义了一个变量﹐那么这个变量的值﹐只影响这个子程序本身以及它自己的子程序﹐而永远不会影像到父程序或父程序产生的其它子程序。 (这也正是我们通常用用export命令修改PATH路径的原因)
比方说﹐您在一个程序中定义一个新的变量﹐或改变一个原有变量值﹐在程序结束的时候﹐那它所设定的变量均被取消﹔如果您想将变量值分享给该程序所产生的子 程序﹐您必须用 export 命令才能保留这个变量值﹐除非子程序另外重新定义。但无论如何﹐当前程序所定义的变量值﹐是无法传回父程序那边的。不妨做做如下的实验﹕ 
MYNAME=kenny 
echo $MYNAME 
kenny 
export MYNAME 
# 设定一个变量。 

# 当前的设定值。 
# 用 export 输出变数值。
/bin/bash 
# 再开一个 shell﹐也就是进入子程序中。
echo $MYNAME 
kenny 

# 保留原有设定值。
export MYNAME=netman 
echo $MYNAME 
netman 
# 重新定义设定值﹐同时也用 export 输出。 

# 变数值被新值取代。 
exit 
# 退出子程序﹐返回父程序。 
echo $MYNAME 
kenny 

# 父程序的变量值并没有改变。
关于变量的另一个特性﹐是的变量值是可以继承的。也就是说﹐您可以将一个变量值来设定另外一个变量名称。比方说﹕ 
FIRST_NAME="Kenny" 
MYNAME=$FIRST_NAME
echo $MYNAME 
Kenny
# 定义一个变量。 
# 再定义另一个变量﹐但它的值是第一个变数。

# 第二个变量继承了第一个变数的值。 
另外﹐在定义变量的时候您还要注意一些规则﹕ 

 

·        定义变量时﹐“=”号两边没有空格键﹔ 

·        作为变量的名称﹐只能是字母和数字﹐但不能以数字开头﹔如果名称太长﹐可以用“_”分隔﹔ 

·        预先定义的变量均为大写﹐自定义变量可以混合大小写﹐以更好区别﹔ 

·        只有 Shell 本身定义的变量才能称为环境变量; 

·        如果变量中带有特殊字符﹐必须先行用“\”符号跳脱﹔ 

·        如果变量中带有空白﹐必须使用引号﹐或进行跳脱。

关于后两项﹐或许我们再找些例子来体会一下﹕ 
TOPIC='Q& A'
# 用单引号保留特殊符号和空白 
 
Q1=What\'s\your\ \"topic\"\?
echo $Q1 
What's your "topic"?
  
# 用 \ 将特殊符号(含引号)和空白跳脱出来 

# 跳脱后﹐特殊符号和空白都保留下来。 
 
ANS="Itis $TOPIC."          ------这个地方引起注意:双引号中字符串可以引用变量!
echo $ANS                         ------这种用法比较常见,而下面的单引号的情况宾不常见。
It is Q & A.
  
# 用双引号保留变数值($) 

# 用双引号﹐显示出变量值。 
 
WRONG_ANS='Itis "$TOPIC".'                     -----注意单、双引号的合理使用
echo $WRONG_ANS 
It is "$TOPIC".
 
  
# 用单引号保留特殊符号和空白(同第一行) 

# 用单引号﹐全部保留﹔同时﹕ 
# $ 也当成一般符号保留﹐而非变量值。              ------这个地方引起注意,单引号时$当成一般符号保留!
 
ALT_ANS='the $TOPIC'\ is\ "'$TOPIC'"\.   ------混合了单、双引号有助于理解。
echo $ALT_ANS 
The $TOPIC is 'Q & A'.
 
# 同时混合单引号﹑双引号﹑和跳脱字符 \ 

# 单引号保留全部﹔双引号保留变数值﹔ 
# \ 将特殊符号跳脱出来。 
我这里解释一下最后面的例子好了﹕'the $TOPIC is '"$TOPIC"\.。首先用单引号将 'the $TOPIC is ' 这段文字括好﹐其中用 3 个空格键和一个 $ 符号﹔然后用双引号保留 $TOPIC 的变量值﹔最后用 \ 跳脱小数点。 
在引用 " " 和 ' ' 符号的时候﹐基本上﹐ ' ' 所包括的内容﹐会变成单一的字符串﹐任何特殊字符都失去其特殊的功能﹐而变成一般字符而已﹐但其中不能再使用 ' 符号﹐而在 " " 中间﹐则没有 ' ' 那么严格﹐某些特殊字符﹐例如 $ 号﹐仍然保留着它特殊的功能。您不妨实作一下﹐比较看看 echo ' "$HOME" ' 和 echo " '$HOME' " 的差别。 
Tips﹕在 shell 命令行的跳脱字符“ \ ”其实我们会经常用到的。例如﹐您的一个命令太长﹐一直打下去可能超过一行﹐或是想要整洁的输入命令行﹐您或许想按 Enter 键敲到下一行继续输入。但是﹐当您敲 Enter 键的时候﹐事实上是输入一个 CR(Carriage-Return) 字符﹐一但 shell 读到 CR 字符﹐就会尝试执行这个命令。这时﹐您就可以在输入 Enter 之前先输入 \ 符号﹐就能将 CR 字符也跳脱出来﹐这样 shell 就不会马上执行命令了。这样的命令行﹐我们在 script 中经常看到﹐但您必须知道那代表什么意思。 

*对变量值进行过滤
如果﹐您想对一些变量值进行过滤﹐例如﹕MY_FILE=' ~/tmp/test.sh' ﹐而您想将变数值换成 test.sh (也就是将前面的路径去掉)﹐那您可以将 $MY_FILE 换成 ${MY_FILE##*/}。这是一个变量值字符串过滤﹕## 是用来比对变量前端部份﹐然后 */ 是比对的色样 (也就是任何字母到 / 之间)﹐然后将最长的部份删除掉。您可以参考如下范例﹕ 
当 FNAME="/home/kenny/tmp/test.1.sh" 的时候﹕ 
变量名称
${FNAME}
显示变量值的全部。
/home/kenny/tmp/test.1.sh
${FNAME##/*/}
比对变量值开端﹐如果以 /*/ 开头的话﹐砍掉最长的部份。
                test.1.sh
${FNAME#/*/}
比对变量值开端﹐如果以 /*/ 开头的话﹐砍掉最短的部份。
      kenny/tmp/test.1.sh
${FNAME%.*}
比对变量值末端﹐如果以 .* 结尾的话﹐砍掉最短的部份。
/home/kenny/tmp/test.1   
${FNAME%%.*}
比对变量值末端﹐如果以 .* 结尾的话﹐砍掉最长的部份。
/home/kenny/tmp/test     
${FNAME/sh/bash}
如果在变量值中找到 sh 的话﹐将第一个 sh 换成 bash。
/home/kenny/tmp/test.1.bash
${FNAME//sh/bash}
如果在变量值中找到 sh 的话﹐将全部 sh 换成 bash。
/home/kenny/tmp/test.1.bash
您除了能够对变量进行过滤之外﹐您也能对变量做出限制﹑和改变其变量值﹕ 

------------好好理解,相当不错!!!
字符串没设定
空字符串
使用默认值
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
一开始或许比较难理解上面的两个表格说明的意思﹐真的很混乱~~ 但只要多做一些练习﹐那您就知道怎么使用了。比方说﹕ 
# expr=EXPR 
# unset str 
# var=${str=expr}; echo var=$var str=$str expr=$expr 
var=expr str=expr expr=EXPR 
# var=${str:=expr}; echo var=$var str=$str expr=$expr 
var=expr str=expr expr=EXPR 
# str= 
# var=${str=expr}; echo var=$var str=$str expr=$expr 
var= str= expr=EXPR 
# var=${str:=expr}; echo var=$var str=$str expr=$expr 
var=expr str=expr expr=EXPR 
# str=STR 
# var=${str=expr}; echo var=$var str=$str expr=$expr 
var=STR str=STR expr=EXPR 
# var=${str:=expr}; echo var=$var str=$str expr=$expr 
var=STR str=STR expr=EXPR 
MYSTRING=test 
echo ${MYSTRING?string not set\!} 
test 
MYSTRING= 
echo ${MYSTRING?string not set\!} 
  
unset MYSTRING 
echo ${MYSTRING?string not set\!} 
bash: MYSTRING: string not set! 
请记住这些变量的习性﹐日后您要写 shell script 的时候就不会将变量搞混乱了。假如您想看看当前 shell 的环境变量有哪些﹐您可以输入 set 命令﹔如果只想检查 export 出来的变量﹐可以输入 export 或 env (前者是 shell 默认的输出变数)。 

Bash 设定 
到这里﹐您或许会问﹕shell 的环境变量在哪里定义呢﹖可以调整吗﹖ 
嗯﹐第一个问题我不大了解﹐我猜那是 shell 设计者预设定义好的﹐我们一登录获得 shell 之后就有了。不过﹐第二个问题﹐我却可以肯定答复您﹕您可以随时调整您的环境变量。您可以在进入 shell 之后用在命令行里面重新定义﹐也可以透过一些 shell 配置文件来设定。 
先让我们看看﹐当您在进行登录的时候﹐系统会检查哪些档案吧﹕ 

·  /etc/profile﹕首先﹐系统会检查这个文件﹐以定义如下这些变量 ﹕PATH﹑USER﹑LOGNAME﹑MAIL﹑HOSTNAME﹑HISTSIZE﹑INPUTRC。如果您会 shell script (我们后面再讨论)﹐那您应该看得出这些变量是如何定义的。另外﹐还指定了 umask 和 ulimit 的设定﹕umask 大家应该知道了﹐而 ulmimit 呢﹖它是用来限制一个 shell 做能建立的行程数目﹐以避免系统资源被无限制的消耗。最后﹐它还会检查并执行 /etc/profile.d/*.sh 那些 script﹐有兴趣您可以追踪看看。 

·  ~/.bash_profile﹕这里会定义好 USERNAME﹑BASH_ENV﹑PATH。其中的 PATH 除了现有的 $PATH 之外﹐还会再加入用户相关的路径﹐您会发现 root 和普通账号的路径是不一样的﹔而 BASH_ENV 呢﹐仔细点看﹐是下一个要检查的档案﹕ 

·  ~/.bashrc﹕在这个档里面﹐您可以发现一些 alias 设定(哦~~ 原来在这里﹗)。然后﹐您会发现有一行﹕. /etc/bashrc 。在 shell script 中﹐用一个小数点然后然后一个空格键再指向另外一个 script﹐意思是同时执行那个 script 并采用那里的变量设定。 

·  /etc/bashrc﹕基本上﹐这里的设定﹐是所有使用者在获得 shell 的时候都会采用的。这里指定了一些 terminal 设定﹐以及 shell 提示字符等等。 

·  ~/.bash_login﹕如果 ~/.bash_profile 不存在﹐则使用这个档。 

·  ~/.profile﹕如果 ~/.bash_profile 和 ~/.bash_login 都不存在﹐则使用这个档。 

·  ~/.bash_logout﹕这个档通常只有一个命令﹕clear﹐也就是把荧幕显示的内容清掉。如果您想要在注销 shell 的时候﹐会执行一些动作﹐例如﹕清空临时档(假如您有使用到临时档)﹑还原某些设定﹑或是执行某些备份之类的。 
您可以透过修改上面提到的档案﹐来调整您进入 shell 之后的变数值。一般用户可以修改其家目录( ~/ )中的档案﹐以进行个人化的设定﹔而作为 root﹐您可以修改 /etc/下面的档案﹐设定大家共享的变量值。至于 bash 的变量值如何设定﹖有哪些变量﹖各变量的功能如何﹖您打可以执行 man bash 参考手册资料。 
Tips﹕一旦您修改了 /etc/profile 或 ~/.bash_profile 档案﹐其新设定要在下次登录的时候才生效。如果您不想退出﹐又想使用新设定﹐那可以用 source 命令来抓取﹕ 
source ~/.bash_profile

抱歉!评论已关闭.