二、Shell变量
2.1、什么是变量
在小学的时候我们学过数学方程式,例如:已知x=1,y=x+1那么y等于多少
在上述的题目中x和y被称为未知数,但是在shell编程里它们是变量名,等号右边的1和x+1是变量的内容,(这里“=”被称为赋值)
通过上面的介绍可以得出,变量就是用一个固定的字符串代替更多,更复杂的内容,该内容包含变量、路径、字符串等其他的内容,变量是暂时存储数据的地方和标记,所存储的数据存在内存空间中,通过调用内容空间的变量名字就可以取出变量对应的数据。使用变量最大的好处就是方便,当然,除了方便以外,很多时候在变成中使用变量也是必须的,否则就无法完成开发工作了。
[[email protected] ~]# blog=zhang789 # 创建变量 [[email protected] ~]# echo $blog # 输出变量 zhang789
变量分为两种,环境变量(全局变量)和普通变量(局部变量)
1、 环境变量也可以称为全局变量,可以在创建他们的shell及其派生出来的任意子进程shell中使用,环境变量又可以分为用户自定义变量和bash内置的环境变量 2、 普通变量也可以称为局部变量,只能在创建它们的shell函数活shell脚本中使用,普通变量一半都是由开发者在开发程序时创建
2.2、环境变量
环境变量用于定义shell的运行环境,保证Shell命令的正确执行,通过环境变量来确定登陆用户名、命令路径、终端类型、登陆目录等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器、Shell脚本和各类应用。
环境变量可以在命令行中设置,当用户退出时这些变量值也会丢失,因此最好在用户家目录下的.bash_profile文件中或全局配置/etc/bashrc,/etc/profile文件或者/etc/profile.d/中定义。将环境变量放入上述的文件中,每次用户登陆时这些变量值都将被初始化。
传统上,所有环境变量均为大写。环境变量应用于用户进程前,都应该用export命令导出,例如:export AS=1
环境变量可用在创建他们的shell和从该shell产生的任意子shell或进程中。他们通常被称为全局变量以区别局部变量。通常,环境变量应该大写。环境变量是已经用export内置命令导出的变量。
有一些环境变量,比如HOME、PATH、SHELL、UID、USER等,在用户登陆之前就已经被/bin/login程序设置好了。通常环境变量定义并保存在用户家目录下的.bash_profile文件中。
可以通过一下的命令查看环境变量
1. env(只显示全局变量) 2. set(所有的变量) 3. declare(所有变量,包括函数、整数和已导出的)
环境变量设置的常用文件及区别
1、用户的环境变量配置
[[email protected] ~]# ll /root/.bash_profile -rw-r--r--. 1 root root 176 12月 29 2013 /root/.bash_profile [[email protected] ~]# ll /root/.bashrc -rw-r--r--. 1 root root 176 12月 29 2013 /root/.bashrc
2、全局环境变量的配置
[[email protected] ~]# ll /etc/profile -rw-r--r--. 1 root root 1750 6月 7 2013 /etc/profile [[email protected] ~]# ll /etc/bashrc -rw-r--r--. 1 root root 2835 8月 12 2015 /etc/bashrc
用户登陆后加载的内容,可以在跳板机上操作,让每切换一次用户就显示当前登陆的USER and IP切换或者登陆用户时提示信息
[[email protected] ~]# cd /etc/profile.d/ [[email protected] profile.d]# cat hello.sh echo "Hello Zhanghe" echo "Blog:zhang789.blog.51cto.com" # 退出重新登录下 [email protected]‘s password: Last login: Fri Jun 9 17:32:13 2017 from 192.168.102.1 Hello Zhanghe #我们输出的信息 Blog:zhang789.blog.51cto.com #作者的博客地址 [[email protected] ~]#
用户第一次登陆时提示,只能是字符串
Last login: Thu Apr 2 12:15:21 2015 from 10.0.0.122 welcome to Ubuntu linux training ! $ cat /etc/motd welcome to Ubuntu linux training !
2.3、定义全局变量
[[email protected] ~]# export BLOG_NAME=‘zhang789.blog.51cto.com‘ [[email protected] ~]# echo $BLOG_NAME zhang789.blog.51cto.com [[email protected] ~]# ZABBIX=3.2 [[email protected] ~]# export ZABBIX [[email protected] ~]# env | grep ZABBIX ZABBIX=3.2 [[email protected] ~]# env | grep BLOG_NAME BLOG_NAME=zhang789.blog.51cto.com [[email protected] ~]# export LANG=EN #更改语言的环境变量 [[email protected] ~]# declare -x NAME=zhanghe
2.3.1、显示与取消环境变量
设置与取消环境变量 [[email protected] ~]# export Blog=zhang789 [[email protected] ~]# echo $Blog zhang789 [[email protected] ~]# unset Blog [[email protected] ~]# echo $Blog [[email protected] ~]# [[email protected] ~]# unset BLOG_NAME [[email protected] ~]# env | grep BLOG_NAME [[email protected] ~]#
常见系统环境变量
2.3.2、环境变量初始化与对应文件的生效顺序
在登录Linux系统并启动一个bash shell时,默认情况下bash会在若干个文件中查找环境变量的设置,这些文件可统称为系统环境文件,bash检查的环境变量文件的情况取决系统运行shell的方式,系统运行shell的方式一般有3种
1、 通过系统用户登录后默认运行的sell
2、 非登录交互式运行的shell
3、 执行脚本运行的非交互式shel
登录加载顺序
1、 系统登录系统后会首先加载/etc/profile全局环境变量文件,这是Linux系统上面默认的shell主环境变量文件,系统上面每个登录用户都会加载这个文件 2、 当加载完/etc/profile文件后,才会执行/etc/profile.d目录下的脚本文件,这个目录下的脚本文件有很多,例如:系统的字符集设置(/etc/sysconfig/i18n)等。 3、 后面开始运行$HOME/.bash_profile(用户环境变量文件),在这个文件中,又会去找$HOME/.bashrc(用户环境变量文件),如果有,则执行,如果没有,则不执行,在$HOME/.bashrc文件中又会去找/etc/bashrc(全局环境变量文件)如果有,则执行,如果没有,则不执行
如果用户的shell不是登录启动的(比如敲bash或者其他不输入用户名密码登录及远程SSH连接情况)这种只会加载$HOME/.bashrc(用户环境变量文件)并找/etc/bashrc(全局环境变量文件)
2.4、定义本地变量
本地变量在用户当前的Shell生存期额脚本中使用。例如,本地变量Blog取值为zhang789,这个值只在用户当前Shell生存期中有意义,如果在shell中启动另一个进程或退出,本地变量Blog值无效。
普通字符串变量定义:
变量名=value 变量名=‘value‘ 变量名="value" 命令变量定义 变量名=$() 变量名=``
shell中变量明的要求
一般是由字母,数字,下划线组成,以字母开头
例1
[[email protected] ~]# a=192.168.1.1 [[email protected] ~]# b=‘192.168.1.1‘ [[email protected] ~]# c="192.168.1.1" [[email protected] ~]# echo "a=$a" a=192.168.1.1 [[email protected] ~]# echo "b=$b" b=192.168.1.1 [[email protected] ~]# echo "c=${c}" c=192.168.1.1
例2
[[email protected] ~]# a=192.168.1.2-$a [[email protected] ~]# b=‘192.168.1.2-$a‘ [[email protected] ~]# c="192.168.1.2-$a" [[email protected] ~]# echo "a=$a" a=192.168.1.2-192.168.1.1 [[email protected] ~]# echo "b=$b" b=192.168.1.2-$a [[email protected] ~]# echo "c=${c}" c=192.168.1.2-192.168.1.2-192.168.1.1
提示:
- 第一种定义a变量的方式是直接指定变量内容,内容一般为简单连续的数字、字符串、路径明等。
- 第二种定义b变量的方式是通过单引号定义变量。这个方式会 的特点是:输出变量时引号里是什么就输出什么,即使内容中有变量也会把变量原样输出,此方法比较适合定义显示纯字符串。
- 第三种定义c变量方式是通过双引号定义变量。这个方式的特点是:输出变量时引号里的变量会经过解析后输出该变量内容。而不是把引号中变量名元杨树称呼,适合于字符串中附带有变量的内容的定义。
-
习惯:数字不加引号,其他默认加双引号
2.5、定义变量单引号、双引号于不加引号
有关单引号、双引号与不加引号的简要说明如下:
范例
[[email protected] ~]# echo ‘today is date‘ today is date # 单引号看到什么就输出什么 [[email protected] ~]# echo ‘today is `date`‘ today is `date` # 单引号看到什么就输出什么 [[email protected] ~]# echo "today is date" today is date # 双引号时如果里面是变量,会先把变量解析成具体内容显示 [[email protected] ~]# echo "today is `date`" today is Wed Apr 1 15:46:18 CST 2015 # 双引号时如果里面是变量,会先把变量解析成具体内容显示 [[email protected] ~]# echo "today is $(date)" today is Wed Apr 1 15:46:24 CST 2015 # 双引号时如果里面是变量,会先把变量解析成具体内容显示 # 对于连续的字符串等内容一般不加引号也可,加双引号一般比较保险,推荐。
变量定义后,调用时测试
[[email protected] ~]# Blog=zhang789 #-->创建一个不带引号的变量 [[email protected] ~]# echo $Blog #-->不加引号,显示一个变量解析后的内容 zhang789 [[email protected] ~]# echo ‘$Blog‘ #-->单引号,显示一个变量本身 $Blog [[email protected] ~]# echo "$Blog" #-->双引号,显示一个变量内容,引号内可以是变量、字符串等 zhang789 [[email protected] ~]# ETT=123 [[email protected] ~]# awk ‘BEGIN {print "$ETT"}‘ $ETT [[email protected] ~]# awk "BEGIN {print "$ETT"}" 123 [[email protected] ~]# awk ‘BEGIN {print ‘$ETT‘}‘ 123
自定义普通字符串变量的建议
1、内容时纯数字(不带空格),定义方式可以不加引号(单或双)
ZHANG=33 HE=yes
2、没特殊情况,字符串一般用双引号定义,特别是多个字符串中间有空格时
NFSD_MODULE=”no load” MyNAME=”ZHANG is a handsome boy.”
3、变量内容需要原样输出时,要用单引号(“) 例如:
BLOG_NAME=’ZHANG’
2.7、变量的命名规范
- 变量命名要统一,使用全部大写字母,语句要清晰,能够正确表达变量内容的含义,过长的英文单词可采用前几个字符代替,多个单词连接使用_号链接,引用时,最好以加大括号或{APACHE_ERR_NUM}”外面加双引号方式引用变量。
- 避免无意义字符或数字:例如下面的COUNT,并不知道其确切含义;
范例:COUNT的不确切定义
CONUT=`grep keywords file` if [ ${CONUT} -ne 22 ] then echo “Do Something” fi
全局变量和局部变量命名
1、脚本中的全局变量定义,如ZHANG_HOME或ZHANGHOME,在变量使用时使用{ }将变量括起或”{ZHANG_HOME}”
范例:操作系统函数库脚本内容全局变量截取例子
$ cat /etc/init.d/functions
2、脚本中局部变量定义:存在于脚本函数(function)中的变量称为局部变量,要以local方式进行声明,使只只在本函数作用域内有效,防止变量在函数中的命名与变量外部程序中变量重名造成异常.
2.1、函数中的变量定义
checkpid() { local i for i in $* ; do [ -d "/proc/$i" ] && return 0 done return 1 }
2.2、变量合并
当某些变量或配置项要组合起来才有意义时,如文件的路径和文件名称,建议将要组合的变量合并到一起赋值给一个新的变量,这样既方便之后的调用,也为以后进行修改提供了方便。
范例:自动化安装httpd的脚本变量合并定义
VERSION="2.2.22" SOFTWARE_NAME="httpd" SOFTWARE_FULLNAME="${SOFTWARE_NAME}-${VERSION}.tar.gz"
2.3、变量定义总结:多学习模仿操作系统自带的/etc/init.d/function函数库脚本的定义思路。
- 1、变量名只能为字母,数字,下划线,字母开头。
- 2、规范的变量名定义方法:见名只意
a) ZHANGEAge=1 每个单词的首字母大写
b) ZHANGE_age=1 单词之间用”_”
c) ZHANGEAgeSex=1 驼峰语法:首个单词的首字母小写,其余单词首字母大写 - 3、=号的知识,a=1等号是赋值的意思
- 4、比较是不是相等,为==打印变量,变量名前接$符号,变量名后面紧接着字符的时候,要用大括号括起来
- 5、注意变量内容引用方法,一般用引号,简单连续字符串可以不加引号,希望原样输出,使用单引号。
- 6、变量内容是命令,这个时候要用反引号或者$()把变量括起来使用。
2.8、特殊变量
2.8.1、位置变量
在shell中存在一些特殊且重要的变量,例如:$1,$#,我们称之为特殊位置变量,要从命令行、函数或脚本执行的时候传递参数
判断参数的个数 $ cat tejing4.sh [ $# -ne 2 ] && { echo "muse two" exit 1 } echo $1 $2
第二个脚本
$ cat tejing5.sh #no1 if [ $# -ne 2 ] then echo "USAGE:/bin/sh $0 arg1 arg2" exit 1 fi #no2 echo $1 $2
控制用户传参个数
$ cat a.sh #!/bin/bash [ $# -ne 2 ] &&{ echo "muse two" exit 1 } echo zhang789 $ sh a.sh sa muse two $ sh a.sh sa ha zhang789
*和@的区别例子
- 将所有的命令行所有参数视为单个字符串,等同于13,$*;
- 将命令行每个参数视为单独的字符串,等同于1 3。这是将参数传递给其他程序的最佳方式,因为他会保留所有内嵌在每个参数里的任何空白。
上述区别仅在于双引号的时候,即和@.
$ set -- "I am" handsome ansheng. # 传入三个参数 $ echo $# # 现在有三个参数 3 $ for i in "$*";do echo $i;done # 在有双引号的情况下,参数里因好内内容当作一个参数输出了,这才真正符号我们传入的参数需求,set -- "I am" handsome ansheng. I am handsome ansheng. $ for i in "[email protected]";do echo $i;done # 在有双引号的情况下,每个参数独立输出 I am handsome ansheng. $ for i ;do echo $i;done # 去掉in变量列表,相当于in “[email protected]” I am handsome ansheng. $ for i in $*;do echo $i;done # 不加双引号,把所有参数输出,然后第一个参数“I am”也拆开输出了. $ for i in [email protected];do echo $i;done # 不加双引号,把所有参数输出,然后第一个参数“I am”也拆开输出了.
2.8.2、进程状态变量
通过脚本控制错误返回值
$ cat fanhui.sh exit 100 $ sh fanhui.sh $ echo $? 100
$$案例应用案例:当系统中只能有某个脚本同时只能运行一个进程的时候。
#!/bin/sh pidpath=/tmp/a.pid if [ -f "$pidpath" ] then kill -USR2 `cat $pidpath` >/dev/null 2>&1 rm -f $pidpath fi echo $$ >$pidpath sleep 300
$_
$ /etc/init.d/ntpd start Starting ntpd: [ OK ] $ echo $_ start
2.9、shell变量子串
常用操作如下表:man bash找本节资料“Parameter Expansion”
${#string} 返回$string的长度 ${string:position} 在$string中,从位置$position之后开始提取子串 ${string:position:length} 在$string中,从位置$position之后开始提取长度为$length的子串 ${string#substring} 从变量$string开头开始删除最短匹配$substring子串 ${string##substring } 从变量$string开头开始删除最长匹配$substring子串 ${string%substring} 从变量$string结尾开始删除最短匹配$substring子串 ${string%%substring} 从变量$string结尾开始删除最长匹配$substring子串 ${parameter/pattern/string} 使用string,来代替第一个匹配的pattern ${parameter/#pattern/string} 从开头匹配string变量中的pattern,使用string来替换匹配的pettern ${parameter/%patter/string} 从结尾开始匹配string变量中的pattern,就用string来替换匹配pattern ${parameter//pattern/string} 使用string,来代替所有匹配的pattern 更多资料man bansh 查找“Parameter Expansion”
2.9.1、${#string}获取变量字符串的长度
[[email protected] ~]# OLDBOY="I am oldboy" [[email protected] ~]# echo $OLDBOY I am oldboy [[email protected] ~]# echo $OLDBOY|wc -L 11 [[email protected] ~]# echo ${#OLDBOY} 11 [[email protected] ~]# expr length "$OLDBOY" 11
打印字符小于6的行
$ cat ab.sh for n in I am ansheng linux welcome to our training. do if [ ${#n} -lt 6 ] then echo $n fi done $ sh ab.sh I am linux to our
2.9.2、输出整个字符串的一部分
${string:position} $ ansheng="I am ansheng" $ echo ${ansheng:2} ${string:position:length} am ansheng $ echo ${ansheng:2:2} am
2.9.3、##
$ echo ${ansheng#a*c} ABC123ABCabc $ echo $ansheng abcABC123ABCabc $ echo ${ansheng##a*c}
2.9.4、%%
$ echo $ansheng abcABC123ABCabc $ echo ${ansheng%a*c} abcABC123ABC $ echo ${ansheng%%a*c} $ echo ${ansheng%C*bc} abcABC123AB $ echo ${ansheng%%C*bc} abcAB
2.9.5、/替换
$ ansheng=abcABC123ABCabc $ echo $ansheng abcABC123ABCabc $ echo ${ansheng/abc/ansheng} anshengABC123ABCabc $ echo ${ansheng/#abc/ansheng} anshengABC123ABCabc $ echo ${ansheng/%abc/ansheng} abcABC123ABCansheng
案例:批量改名
$ f=stu_102999_5_finished.jpg $ echo $f stu_102999_5_finished.jpg $ echo ${f/_finished//} stu_102999_5/.jpg $ echo ${f/_finished/} stu_102999_5.jpg $ f=stu_102999_5_finished.jpg $ echo ${f/_finished/} stu_102999_5.jpg $ mv $f `echo ${f/_finished/} ` $ ls -lrt|tail -5 -rw-r--r-- 1 root root 0 4月 2 16:59 stu_102999_5.jpg -rw-r--r-- 1 root root 0 4月 2 16:59 stu_102999_4_finished.jpg -rw-r--r-- 1 root root 0 4月 2 16:59 stu_102999_3_finished.jpg -rw-r--r-- 1 root root 0 4月 2 16:59 stu_102999_2_finished.jpg -rw-r--r-- 1 root root 0 4月 2 16:59 stu_102999_1_finished.jpg $ for f in `ls *fin*.jpg`;do mv $f `echo ${f/_finished/}`;done $ ls -lrt|tail -5 -rw-r--r-- 1 root root 0 4月 2 16:59 stu_102999_5.jpg -rw-r--r-- 1 root root 0 4月 2 16:59 stu_102999_4.jpg -rw-r--r-- 1 root root 0 4月 2 16:59 stu_102999_3.jpg -rw-r--r-- 1 root root 0 4月 2 16:59 stu_102999_2.jpg -rw-r--r-- 1 root root 0 4月 2 16:59 stu_102999_1.jpg
小结:
#是开头删除匹配最短 ##是开头删除匹配最长 %是结尾删除匹配最短 %%是结尾删除匹配最长