Shell编程从入门到精通-第二章.shell变量

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell编程从入门到精通-第二章.shell变量相关的知识,希望对你有一定的参考价值。

二、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

提示:

  1. 第一种定义a变量的方式是直接指定变量内容,内容一般为简单连续的数字、字符串、路径明等。

  2. 第二种定义b变量的方式是通过单引号定义变量。这个方式会 的特点是:输出变量时引号里是什么就输出什么,即使内容中有变量也会把变量原样输出,此方法比较适合定义显示纯字符串。

  3. 第三种定义c变量方式是通过双引号定义变量。这个方式的特点是:输出变量时引号里的变量会经过解析后输出该变量内容。而不是把引号中变量名元杨树称呼,适合于字符串中附带有变量的内容的定义。 

  4.  习惯:数字不加引号,其他默认加双引号

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、变量的命名规范

  1. 变量命名要统一,使用全部大写字母,语句要清晰,能够正确表达变量内容的含义,过长的英文单词可采用前几个字符代替,多个单词连接使用_号链接,引用时,最好以加大括号或{APACHE_ERR_NUM}”外面加双引号方式引用变量。

  2. 避免无意义字符或数字:例如下面的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. 1、变量名只能为字母,数字,下划线,字母开头。

  2. 2、规范的变量名定义方法:见名只意 
        a) ZHANGEAge=1 每个单词的首字母大写
        b) ZHANGE_age=1 单词之间用”_” 
        c) ZHANGEAgeSex=1 驼峰语法:首个单词的首字母小写,其余单词首字母大写

  3. 3、=号的知识,a=1等号是赋值的意思

  4. 4、比较是不是相等,为==打印变量,变量名前接$符号,变量名后面紧接着字符的时候,要用大括号括起来

  5. 5、注意变量内容引用方法,一般用引号,简单连续字符串可以不加引号,希望原样输出,使用单引号。

  6. 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

*和@的区别例子

  1. 将所有的命令行所有参数视为单个字符串,等同于13,$*;

  2. 将命令行每个参数视为单独的字符串,等同于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

小结:

#是开头删除匹配最短  
##是开头删除匹配最长  
%是结尾删除匹配最短 
%%是结尾删除匹配最长


本文出自 “家住海边喜欢浪” 博客,请务必保留此出处http://zhang789.blog.51cto.com/11045979/1934822

以上是关于Shell编程从入门到精通-第二章.shell变量的主要内容,如果未能解决你的问题,请参考以下文章

Shell编程Shell从入门到精通

shell从入门到精通(-1)初次会面运行第一个shell脚本

shell从入门到精通(16)shell 退出状态码(特殊变量$?)

shell从入门到精通(15)shell 退出状态码(特殊变量$?)

shell从入门到精通(32)优秀的shell编程习惯和规范

shell从入门到精通(32)优秀的shell编程习惯和规范