提示:如果希望一个用户定义的变量能够在定义它的shell脚本以外使用,就必须使用export命令。例如,“export var”命令就是将用户定义的变量var添加到系统变量列表中,这样就可以在定义var变量脚本以外的地方使用。
在Linux的bash中可以使用set命令来查看系统当前的环境变量及其取值。如下图所示。
说明:由于Linux的环境变量很多,这里利用管道符和tail命令与set命令结合只显示系统环境变量的最后10个。
若要查看当前某个环境变量的值,可以使用echo命令,并在环境变量的前面加上“$”即可。例如,查看当前的命令主提示符,可以输入如下命令: [root@myhost root]# echo $PS1
命令主提示符是Linux的shell程序为用户输入命令而设置的提示符。环境变量PS1的值就是命令主提示符,默认为“[\%u@\\h \\W]\\$”,其中“[”、“]”和“@”原样显示; \%u”相应位置显示当前登录的用户账号;“\\h”表示相应位置显示主机名;“\\W”相应位置当前工作目录;“\\$”表示如果当前登录账号是超级用户就显示“#”,如果是普通用户就显示“$”。例如,当超级用户登录myhost主机时,命令提示符显示为“[root@myhost root]#”。 环境变量PATH记录了命令执行时的默认的搜索路径,即当用户在命令提示符后输入命令时,Linux系统会按照PATH设置的路径搜索该命令,然后再执行该命令。PATH变量的值由多个路径组成,各路径之间使用“:”隔开。 shell配置文件
用户可以通过set命令来查看和设置常用的环境变量,但是在系统启动的时候,Linux并不是通过set命令来设置这些变量的,而是通过读取相应的shell配置文件来获取环境变量的值的。在Linux的bash中其配置文件有全局的配置文件,也有用户个人的配置文件,shell在检查这些文件的时候,遵循如下的顺序:/etc/profile→~/.bashrc_profile→~/.bashrc→/etc/bashrc。其中/etc/profile和/etc/bashrc文件中包含了全局环境变量的设置,~/.bashrc_profile和~/.bashrc文件中包含了个人环境变量的设置。 1./etc/profile文件
etc/profile文件是系统登录时最先检查执行的shell配置文件,也是Linux系统最主要的shell配置文件,有关系统最重要的环境变量都在此定义,如当前系统的PATH、USER、LOGNAME、MAIL和HOSTNAME等。在该文件中还定义了每个shell所能执行的程序的数目,即ulimit变量,以免shell过度占用系统资源。另外,在/etc/profile文件末尾会自动执行/etc/profile.d目录下的所有*.sh脚本。 2. ~/.bashrc_profile
每个系统用户的子目录下都有一个.bashrc_profile文件,用于设置每个用户的bash环境变量,Linux系统启动时,在读取/etc/profile文件的内容之后,就会检查该文件
在该文件中,首先读取并执行~/.bashrc文件,然后设置PATH、BASH_ENV和USERNAME的值。此处的
PATH变量的值,除了在全局环境配置文件/etc/profile文件中设置的PATH的值以外,还添加了用户主目录下的bin目录。BASH_ENV的值则是接下来需要检查的文件的名称。 3. ~/.bashrc
在读取~/.bashrc_profile文件的过程中,Linux会在执行~/.bashrc_profile文件的内部中调用并执行~/.bashrc文件。另外,与前面两个文件不同,Linux系统每次用户登录bash的时候都会读取~/.bashrc文件,并重新设置该文件中定义的环境变量。而/etc/profile和~/.bashrc_profile只在系统启动的时候才读取。在~/.bashrc文件中只定义了某些别名命令和虚拟终端的设置。例如,如果telnet登录时,无法浏览超过一页的信息或文件内容,此时可以在该文件中添加如下行: export TERM=vt100
另外在该文件的最后还检查/etc/bashrc文件是否存在,如果存在则转而读取并执行该文件。 ./etc/bashrc
和~/.bashrc文件一样,用户每次登录Linux系统的时候,都会自动读取并执行该文件。在该文件中设置了系统创建文件时默认的文件存取权限的掩码umask的值和用户自定义的命令提示符PS1。
除了上面介绍的常用的环境变量配置文件以外,还有~/.bash_login、~/.profile、~/.bash_logout和~/.bash_history文件,用于系统环境变量的定义。如果~/.bash_profile文件不存在时,系统会转而读取~/.bashrc文件。该文件在每次用户登录时都会被bash读取并执行。通常可以将用户登录后必须执行的命令存放在这个文件中。如果~/.bash_profile和~/.bash_login文件都不存在的情况下,系统会使用~/.profile文件中的内容设置当前环境变量的值,其功能与~/.bash_profile文件完全相同。
Linux系统在注销前,bash会读取并执行~/.bash_logout。通常该文件中只有一个clear清屏命令。如果希望在系统注销前执行一些特定的任务,就可以将相应的命令行写入该文件。 ~/.bash_history文件用于记录当前用户在登录系统后所执行过的命令。
shell脚本编程:
shell脚本程序,简称shell脚本或shell程序,是使用系统提供的命令编写的文本文件,该文件具有可执行的属性,能够帮助系统管理员自动管理系统。在Linux的发行版本中就包含了很多的shell程序,这些脚本有的是为了完成系统参数的设置,例如前面介绍的/etc/profile等文件;有的是为了完成某项系统服务的启动工作,例如/etc/rc.d/init.d目录下的所有脚本。 shell变量
shell程序语法和其他高级语言程序类似,包括变量、控制结构和函数等。 1.变量类型与使用
bash脚本是一种弱类型的脚本语言。所谓弱类型脚本语言,就是在bash脚本中,对类型的要求不严格,同一个变量可以随着使用场合的不同,存储不同类型的数据。弱类型语言变量使用灵活,但是编程者需要注意对变量当前存储的数据类型的检查。 1)变量的声明
在bash中,变量的使用不需要显式的声明,或者说赋值就可以认为是变量的声明。通常,给一个变量赋值应采用如下的格式: 变量名=值
注意:等号两边不能存在分隔符(包括空格,制表位和回车符)。 2)变量的引用
通常,要引用一个变量,可以采取在变量名前加一个$的方法,即“$变量名”。 例如,要引用上面定义的变量a1可以采用如下的方法: echo \
但是,有时候这种方法会产生混淆。例如,希望使用变量a1来输入“hello Linux”字符串。如果使用echo “$a1Linux”就会得不到期待的字符。这是因为bash把“a1Linux”作为一个变量来处理了。此时可以选择使用以下的几种用法(其
中,value代表一个变量可能取的具体的值):
? ${变量var:-value}:如果指定的变量var存在,则返回var的值,否则返回value。
? ${变量var:=value}:如果指定的变量var存在,则返回var的值,否则先将value赋给var,然后再返回value。 ? ${变量var:+value}:如果指定的变量var存在,则返回value,否则返回空值。
? ${变量var:?value}:如果指定的变量var存在,则返回该var的值,否则将错误提示消息value送到标准错误输
出并退出shell程序。
? ${变量var:offset[:length]}:offset和length是整数,中括号表示可选部分。表示返回从变量var的第offset+1个
字符开始长度为length的子串。如果中括号部分省略,则表示返回变量var第offset+1个字符后面的子串。 ? [root@myhost root]# echo $var ${title:-\? hello marry!
? 变量title在前面都没有被赋值,所以${title:-\返回“marry”。 ? [root@myhost root]# echo $var ${title:+\? hello !
? 变量title仍然没有被赋值,即不存在,所以${title:+\返回空值。 ? [root@myhost root]# echo $var ${title:?\? bash: title: title is null or empty
? 变量title仍然没有被赋值,即不存在,所以${title:?\返回了错误信息,即“bash: title: title is
null or empty”。
? [root@myhost root]# echo $var ${title:=\? hello tom and marry!
? 到此为止变量title仍然没有被定义,所以title被赋值为“tom and marry”,并返回该值。 ? [root@myhost root]# echo $var ${title:+\? hello somebody!
? 此时变量title已经存在,故返回“somebody”。 ? [root@myhost root]# echo $var ${title:8:5}! ? hello marry!
? 此处变量title已经存在,且值为tom and marry,取其第9个字符,即“m”开始后面5个字符,也就是“marry”。
3)特殊变量
在shell程序中存在一些特殊变量,当shell程序运行时,这些变量能够记录shell程序的命令行参数。这些变量分别是$0、$1、?$n,以及$#、$*和$@。其中$0存放的是命令行的命令名,$1存放的是命令行中传递给命令的第一个参数,依次类推,$n存放的是传递给命令的第n个参数。$#存放传递给命令的参数的个数(不包括命令),$*和$@均用于存放传递给命令的所有参数,两者的区别在于$*把所有的参数作为一个整体,而$@则把所有的参数看作是类似于字符串数组一样,可以单独访问这些参数。 2. shell表达式
和高级程序语言一样,shell程序的表达式由运算符和参加运算的操作数构成。操作数通常可以是变量、常量。 1)shell的运算符
shell的运算符的使用规则都与C语言非常类似。 2)shell表达式
利用运算符将变量或常量连接起来就构成了表达式。但是由于在bash中变量和常量没有特定的数据类型,因此在bash中单纯使用一个表达式作为命令或语句是错误的,而必须使用expr或let命令来指明表达式是一个运算式。expr命令会先求出表达式的值,然后送到标准输出显示。let命令会先求出表达式的值,然后赋值给一个变量,而不显示在标准输出上。expr和let命令的使用方法如下: expr <表达式>
let <表达式1> [表达式2 ...]
expr命令一次携带一个表达式,let命令一次可以携带多个表达式。在expr命令的表达式中使用了数值运算,此时需要用空格将数字运算符与操作数分隔开。另外,如果表达式中的运算符是“<”、“>”、“&”、“*”及“|”等特殊符号,需要使用双引号、单引号括起来,或将反斜杠(\\)放在这些符号的前面。而let命令中的多个表达式之间需要空格隔开,而表达式内部无需使用空格。例如如下几个表达式: ? expr 3+2
操作数3、2和运算符+之间没有空格,此时bash不会报错,而是把3+2作为字符串来处理。 ? expr 3 + 2
操作数3、2和运算符+之间有空格,此时bash认为是数字运算,返回5送到标准输出设备。 ? expr 3\
使用双引号将操作符*括起,此时bash返回乘积6。 ? let s=(2+3)*4
s结果为5*4=20。 3.条件判断
在编写程序的时候,经常需要根据某个条件的测试进行程序执行分支的选择。这里的条件可能是某个表达式的值、文件的存取权限、某段代码的执行结果,或者是多个条件结果按照逻辑运算后的值。条件测试的结果只有真或假2种。需要注意的是,这里“真”的数值表示为0,“假”的数值表示为非0,与表达式的真值以及C语言的真值刚好相反。
在bash中条件测试的使用方法是,利用test命令或一对中括号[]包含条件测试表达式,这两种方法是等价的。它们的格式如下: test cond_expr 或 [ cond_expr ]
注意:利用一对中括号时,左右的中括号与表达式之间都必须存在空格。 cond_expr是需要测试的条件表达式,可以是以下几种情况: (1)文件存取属性测试:包括文件类型,文件的访问权限等。 (2)字符串属性测试,包括字符串长度,内容等。 (3)整数关系测试,包括大小比较,相等判断等。 (4)上述3种关系通过逻辑运算(与、或、非)的组合
shell控制结构
shell程序的控制结构是用于改变shell程序执行流程的结构。在shell程序的执行过程中可以根据某个条件的测试值,来选择程序执行的路径。在shell程序中,控制结构可以简单地分为分支和循环结构2类。bash支持的分支结构有if结构和case结构,支持的循环结构有for结构、while结构和until结构。它们的使用方法与C语言等高级程序设计语言中相应的结构类似。 1.if分支结构
if结构是最常用的分支结构,其格式如下: if 条件测试1 ; then then [else fi
command_list_3 ] command_list_2 ] command_list_1 [elif 条件测试2 ;
其中,中括号部分为可选部分。当“条件测试1”为真时,执行command_list_1,否则如果存在elif语句,则测试“条件测试2”,如果为真,执行command_list_2。如果elif语句不存在或“条件测试2为假,则执行command_list_3。条件测试部分一般可以是test或[]修饰的条件表达式。
例6-5 根据用户输入的目录名称判断该目录是否存在,如果存在则进入该目录,否则测试同名文件是否存在,如果存在,则退出shell程序,否则新建同名目录,并进入该目录。 #!/bin/bash
#an example script of if clear
echo \ read dir_name
#测试$dir_name目录是否存在 if [ –d $dir_name ] ; then
cd $dir_name > /dev/null 2>$1
echo \
#测试是否存在与$dir_name同名的文件 elif [ -f $dir_name ] ; then else fi
在该例中,“cd $dir_name > /dev/null 2>$1”表示cd命令可能产生的标准输出信息和标准错误输出信息重定向的到一个空设备/dev/null,从而实现隐藏cd命令错误输出的功能。“mkdir $dir_name > /dev/null 2>$1”命令行的作用类似。由于Linux不允许在同一目录下存在同名的文件和目录,所有如果$dir_name不存在时,还要测试是否有同名的文件存在,然后才能新建该目录。
注意:then命令可以和if结构写在同一行,但是如果then命令和if结构在同一行时,then命令的前面一定要有一个分号,且分号与条件测试表达式之间用空格隔开。 2.case分支结构
if结构用于存在两种分支选择的情况下,当程序存在多个分支的选择时,如果使用if结构,就必须使用多个elif结构,从而使得程序的结构冗余,此时可以选在使用case结构。case结构可以帮助程序灵活地完成多路分支的选择,而且程序结构直观、简洁。case分支结构的格式如下: case expr 模式1 )
command_list_1 …… * )
;;
command_list_2 ;; [ 模式2 )
mkdir $dir_name > /dev/null 2>$1 cd $dir_name
echo \echo \exit