RHCE的学习(18)
第二章 变量和引用
深入认识变量
在程序设计语言中,变量是一个非常重要的概念。也是初学者在进行Shell程序设计之前必须掌握的一个非常基础的概念。只有理解变量的使用方法,才能设计出良好的程序。本节将介绍Shell中变量的相关知识。
什么是变量
-
顾名思义,变量就是程序设计语言中的一个可以变化的量,当然,可以变化的是变量的值。变量几乎所有的程序设计语言中都有定义,并且其涵义也大同小异。
-
从本质上讲,变量是在程序中保存用户数据的一段内存存储空间,变量名是内存空间的首地址
-
在程序的执行过程中,保存数据的内存空间的内容可能会不断地发生变化,但是,代表内存地址的变量名却保持不变。
变量的名称
在Shell中,变量名可以由字母、数字或者下划线组成,并且只能以字母或者下划线开头。对于变量名的长度,Shell并没有做出明确的规定。因此,用户可以使用任意长度的字符串来作为变量名。但是,为了提高程序的可读性,建议用户使用相对较短的字符串作为变量名。
在一个设计良好的程序中,变量的命名有着非常大的学问。通常情况下,用户应该尽可能选择有明确意义的英文单词作为变量名,尽量避免使用拼音或者毫无意义的字符串作为变量名。这样的话,用户通过变量名就可以了解该变量的作用。
-
组成:字母、数字、下划线组成,不能以数字开头
-
变量名称的长度,shell没有明确规定,但是为了增加可读性,建议使用较短的、见名知意的名称命名
-
规则
-
首字符必须为字母或者下划线:a-z,A-Z
-
中间不能由空格,可以使用下划线(_)
-
不能使用标点符号
-
不能使用bash中关键字,输入help查看bash的保留字
-
例:下面的变量名都是很好的选择
-
[root@server ~]# JAVA_HOME=/usr/bin/jvm/jre-1.6.0-openjdk.x86_64
[root@server ~]# SUM=0
[root@server ~]# back_up=/root
[root@server ~]# PATH=/sbin
[root@server ~]# UID=100
[root@server ~]# SSHD=/usr/sbin/sshd
扩展两种方式:
- 驼峰语法
- 小驼峰
- 大驼峰
- 匈牙利命名法
什么是驼峰语法?
骆驼式命名法就是当变量名或函数名是由一个或多个单词连结在一起,而构成的唯一识别字时,(小驼峰)第一个单词以小写字母开始;从第二个单词开始以后的每个单词的首字母都采用大写字母或者大驼峰法把第一个单词是大写,后面的单词首字母也大写例如:myFirstName、MYLastName,这样的变量名看上去就像骆驼峰一样此起彼伏,故得名。
除了驼峰命名法,另外还有匈牙利命名法。基本原则是:变量名=属性+类型+对象描述。匈牙利命名法关键是:标识符的名字以一个或者多个小写字母开头作为前缀;前缀之后的是首字母大写的一个单词或多个单词组合,该单词要指明变量的用途。比如m_lpszStr, 表示指向一个以0字符结尾的字符串的长指针成员变量。属性部分:
属性部分:g_ 全局变量 c_ 常量 m_ c++类成员变量 s_ 静态变量 类型部分: 数组 a 指针 p 函数 fn_另外,有些程序员喜欢用下划线。比如file_name.
变量的类型
-
原则:shell是一种动态类型语言和弱类型语言,即在Shell中,变量的数据类型毋需显示地声明,变量的数据类型会根据不同的操作有所变化。准确地讲,Shell中的变量是不分数据类型的,统一地按照字符串存储。但是根据变量的上下文环境,允许程序执行一些不同的操作,例如字符串的比较和整数的加减等等。
什么是弱类型语言、强类型语言?
- 强类型和弱类型主要是站在变量类型处理的角度进行分类的。
- 强类型是指不允许隐式变量类型转换,弱类型则允许隐式类型转换。
换句话说:
-
强类型语言,当你定义一个变量是某个类型,如果不经过代码显式转换(强制转化)过,它就永远都是这个类型,如果把它当做其他类型来用,就会报错
-
弱类型语言,你想把这个变量当做什么类型来用,就当做什么类型来用,语言的解析器会自动(隐式)转换。
-
比如:
-
C语言定义变量,int+变量名,实则前面的int就似给变量内存划分了等级,int定义整形所以空间里只能存放整形,这就是强类型
-
php、C#和Python等都是强类型语言。
-
变量的分类
在Shell中,通常情况下用户可以直接使用变量,而毋需先进行定义,当用户第一次使用某个变量名时,实际上就同时定义了这个变量,在变量的作用域内,用户都可以使用该变量。
-
shell的变量数据类型
[root@server ~]# vim test1.sh
#!/bin/bash
# 定义变量x,输入初始值123
x=123
# 变量x加1
let "x+=1"
# 输出变量x的值
echo "x=$x"
# 替换x中1的值为abc,并赋值给变量y
y=${x/1/abc}
# 使用declare -i 声明变量y为整型变量(-i 表示整型)
declare -i y
# 输出y的值
echo "y=$y"
[root@server ~]# bash test1.sh
x=124
y=abc24#显示空行
echo
变量的定义
-
原则:直接使用,不需要变量声明
-
格式:变量名=变量的值
-
例:
[root@server ~]# vim test2.sh#!/bin/bash
# 定义变量a
a=1# 定义变量b
b="hello"# 定义变量c
c="hello world"# 定义路径
bak_dir=/data/backup
注:
-
= 前后不能收空格
[root@server ~]# a= 3
bash: 3: command not found...
[root@server ~]# b =5
bash: b: command not found...
-
字符串类型建议使用双引好作为定界符引起,尤其是字符串中有空格
[root@server ~]# stu_name=zhang san
bash: san: command not found...
[root@server ~]# stu_name="zhang san"
[root@server ~]# stu_name='zhang san'
自定义变量
概念:上述以赋值形态形成的变量定义形式称为自定义变量
定义变量:变量名=变量值
变量名必须以字母或下划线开头,区分大小写 ip1=192.168.2.115
本地(自定义变量)变量 环境变量 export
-
引用变量的值:
-
$变量名
-
${表达式或变量名}
-
例:
-
[root@server ~]# a=1024
[root@server ~]# echo $a
1024
[root@server ~]# echo ${a}
1024
-
查看变量
[root@server ~]# set
[root@server ~]# declareecho $变量名
set(所有变量:包括自定义变量和环境变量)
env # 显示当前用户的环境变量
printenv #同上
例如env |grep back_dir2
-
取消变量:unset 变量名
[root@server ~]# a=256
[root@server ~]# echo $a
256
[root@server ~]# unset a
[root@server ~]# echo $a
-
作用范围:只在当前shell起效
环境变量
概念
-
环境变量又称为全局变量,可以在任意子shell生效(当前进程与当前进程的子进程生效),环境变量又分为自定义环境变量和bash内置的环境变量,用户退出命令后改变量会丢失,若需要永久保存就必须写在文件中(/etc/profile.d/*.sh 与 /etc/bashrc)
-
定义环境变量
# 法1
export 环境变量=值# 法2
变量名=值
export 变量名# 法3
declare -x 变量名=值
-
例:
[root@server ~]# export back_dir1=/home/backup 将自定义变量转换成环境变量
[root@server ~]# NAME="zhang san"
[root@server ~]# export NAME
[root@server ~]# declare -x AGE=20
[root@server ~]# env # 显示当前用户的环境变量
[root@server ~]# printenv # 同上
[root@server ~]# export # 同上
-
注意:以上定义的环境变量都是临时的,重启后会失效,若要永久生效,则需要写入到配置文件中
-
对比:
C语言 局部变量 全局变量
shell 自定义变量 环境变量
=========================================
示例:
TZ=Asia/Shanghaiexport TZ设置java环境变量 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html#配置环境变量/etc/profileexport JAVA_HOME=/usr/java/jdk1.6.0_45export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export PATH=$PATH:$JAVA_HOME/bin#使配置生效 #source /etc/profile#检测: # java –versionjava version "1.6.0_45"Java(TM) SE Runtime Environment (build 1.6.0_45-b06)Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode#也可以脚本形式(比如java.sh)定义在/etc/profile.d/下面让环境变量的修改在退出shell再次登陆时仍然有效,需要在相关配置文件中修改。
shell 环境变量存储的文件:
-
bash shell 初始化文件有:/etc/profile、 ~/.bash_profile、 ~/.bash_login、 ~/.profile、 ~/.bashrc、/etc/bashrc
-
如图:
-
/etc/profile :存放一些全局(共有)变量,不管哪个用户,登录时都会读取该文件。通常设置一些Shell变量PATH,USER,HOSTNAME和HISTSIZE等
-
~/.bash_profile:每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次,默认情况下,此文件通过脚本执行同目录下用户的.bashrc文件
-
~/.bashrc:该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取
-
/etc/bashrc:为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取
-
/etc/inputrc文件为特定的情况处理键盘映射
-
执行顺序:/etc/profile-->/etc/profile.d/*.sh--> ~/.bash_profile -->/etc/bashrc-->~./.bashrc
-
结论:
-
对于用户的环境变量设置,常见的是用户家目录下的.bashrc和.bash_profile
-
对于全局环境变量设置,常见的文件有:/etc/profile /etc/bashrc /etc/profile.d 这三个配置文件
-
常用方法是直接在/etc/profile文件中写入全局变量,如果想要在登陆后初始化或者显示加载的内容,只需要把脚本文件放在 /etc/profile.d 文件下即可
-
区别:
bash_profile只会在会话开始(登陆)时读取一次,bashrc文件每次打开终端都会读取。 定义环境变量,配置文件读取顺序
(会继承上一个shell的全部变量)
1)配置文件的执行顺序 su - root
/etc/profile.d/test.sh
/etc/profile
/root/.bashrc
/etc/profile
~/.bash_profile2)登录式shell的配置文件执行顺序
(清除所有变量,通过文件重新读入)
• a.直接通过终端输入账号密码进行登陆
• b.使用su - USERNAME切换用户
执行顺序:(影响该shell的配置文件)
/etc/profile-->/etc/profile.d/*.sh-->/etc/bashrc-->~./.bashrc-->~/.bash_profile3)非登录式shell配置胚子文件执行顺序
• a. su UserName
• b.图形界面打开终端
• c.执行脚本(进入子shell) ./
• d.任何其他的bash实例
执行顺序(影响该shell的配置文件)
~/.bashrc-->/etc/bashrc--->/etc/profile.d/*.sh交互式shell和非交互式shell
交互式:正常的命令行
非交互式shell:shell脚本
扩展:
可以写入配置文件来观察是否读取
[root@bogon ~]# echo "echo /etc/bashrc" >> /etc/bashrc
[root@bogon ~]# echo "echo /etc/profile" >> /etc/profile
[root@bogon ~]# echo "echo ~/.bash_profile" >> ~/.bash_profile
[root@bogon ~]# echo "echo /etc/profile.d/a.sh" >> /etc/profile.d/a.sh
[root@bogon ~]# echo "echo ~/.bashrc" >> ~/.bashrc
bash内置环境变量
- shell程序在运行时,会接受一组变量来确定登录用户名、命令路径、终端类型、登录目录等等,这些变量就是环境变量。
- shell内置的环境变量是所有的shell程序都可以使用的变量,环境变量会影响所有的脚本的执行结果。
变量 | 说明 |
---|---|
PATH | 命令的搜索路径,以冒号作为分隔符 |
HOME | 用户的家目录的路径,是cd命令的默认参数 |
COLUMNS | 命令行编辑模式下可使用命令的长度 |
HISTFILE | 命令历史的文件路径 |
HISTFILESIZE | 命令历史中包含的最大行数 |
HISTSIZE | history命令输出的记录数 |
LOGNAME | 当前用户的名字 |
SHELL | 当前使用的shell |
PWD | 当前的工作目录 |
位置变量
-
概念:当一条命令或脚本执行时,后面可以跟多个参数,可以使用位置变量来表示该参数
-
例:编写一个shell脚本,当命令行或者从其他shell脚本中调用它的时候,这个脚本接受若干参数。这些选项是通过linux作为位置参数提供给shell程序的。在shell脚本中应有变量,接受实参,这类变量的名称很特别分别为1,2,3...这类变量称为位置变量,位置参数1存放在位置变量1中,位置参数2存放在位置变量2中,....来访问。
sh test1.sh hello world 123 456
-
当执行test1.sh 脚本时,第一个参数为hello到第四个参数可以使用特殊的符号表示,如:$1 $2 $3 ……
-
常见的位置变量
$0 : 脚本名
$1-$9 : 1-9个参数
${10} :10以上的参数需要大花括号括起
$* : 所有参数
$@ : 所有参数
$# : 参数个数
$$ : 当前进程的PID
$! : 上一个后台进程的PID
$? : 上一个命令的返回值状态码,0为成功
$_ 匹配上一个命令的最后一参数(注:127找不到命令 2没有文件或目录 )
-
例:
[root@server ~]# vim test3.sh
#!/bin/bash
echo "第2个位置参数是: $2"
echo "第1个位值参数是: $1"
echo "第4个位置参数是: $4"
echo "所有参数是: $*"
echo "所有参数是: $@"
echo "参数的个数是: $#"
echo "当前进程的PID值: $$"
[root@server ~]# bash test3.sh 1 2 3 4 5
第2个位置参数是: 2
第1个位值参数是: 1
第4个位置参数是: 4
所有参数是: 1 2 3 4 5
所有参数是: 1 2 3 4 5
参数的个数是: 5
当前进程的PID值: 2986
[root@server ~]# vim test4.sh
[root@server ~]# bash test4.sh 孙小帅 18 123456@qq.com
name: 孙小帅
age: 18
E-mail:123456@qq.com
- 例2:$?和位置变量
# vim ping.sh
#!/bin/bash
ping -c2 $1 &>/dev/null
if [ $? = 0 ];then echo "host $1 is ok"
else echo "host $1 is fail"
fi
# chmod a+x ping.sh
# ./ping.sh 192.168.2.25
-
$* 与 $@区别
当$* 和 $ @没有被引用的时候,它们确实没有什么区别,都会把位置参数当成一个个体,
"$*"会把所有位置参数当成一个整体(或者说当成一个单词),如果没有位置参数,
则"$* "为空,如果有两个位置参数并且IFS为空格时,"$*"相当于"$1 $2"
"$@"会把所有位置参数当成一个单独的字段,如果没有位置参数($#为0),则"$@"展开为空
(不是空字符串,而是空列表),如果存在一个位置参数,则"$@"相当于"$1",如果有两个参数,
则"$@"相当于"$1" "$2"等等
set -- "I am" test command
--将任何剩余的参数分配给位置参数,如果没有剩余参数,位置参数未设置。
[root@localhost Scripts]# for i in "$*";do echo $i;done
I am test command
[root@localhost Scripts]# for i in "$@";do echo $i;done
I am
test
command
[root@localhost Scripts]# for i;do echo $i;done
I am
test
command
2)temp=‘this is a temped variable’;echo foo${temp},上述命令执行结果
3)下面环境变量($0)表示获取当前执行的shell脚本的文件名。
变量赋值和作用域
显示赋值
-
格式:变量名=变量值
-
例
ip1=192.168.1.251
school="Peking University"
today1=`date +%F` # 注意为反引号``
today2=$(date +%F)
变量和引号
-
双引号:除了$ 、单引号、反引号、发斜线之外,其它被引起的内容保持字面意思
-
单引号:所有字符保持字面意思
-
反引号:被引起的字符串转为shell命令
-
反斜线:转义符(\),屏蔽后面字符的特殊含义
变量的作用域
-
全局变量:全局变量定义在脚本中,也可以定义在函数中,作用范围:从定义的开始处到shell脚本结束或者被显示的去除
-
例:
[root@server ~]# vim test5.sh
#!/bin/bash
func() # 定义函数
{echo "$v1"v1=200
}
v1=100
func
echo "$v1"
[root@server ~]# bash test5.sh
100
200
-
函数内部定义全局变量
# 上例修改
[root@server ~]# vim test5.sh
#!/bin/bash
func() # 定义函数
{v2=200
}
func
echo "$v2"
[root@server ~]# bash test5.sh
200
-
局部变量:范围更小,仅限于某个程序段中,如:函数、shell等,通过local关键字定义,注意:函数的参数也是局部变量
# 上例修改
[root@server ~]# vim test5.sh
#!/bin/bash
func() # 定义函数
{local v3=200 # 使用local关键字声明为局部变量
}
func
echo "$v3"
[root@server ~]# bash test5.sh
-
全局变量和局部变量区别
# 上例修改
[root@server ~]# vim test5.sh
#!/bin/bash
func()
{#输出全局变量v1的值echo "global variable v1 is $v1"#定义局部变量v1local v1=2#输出局部变量v1的值echo "local variable v1 is $v1"
}
#定义全局变量v1
v1=1
#调用函数
func
#输出全局变量v1的值
echo "global variable v1 is $v1"
declare命令
declare为shell指令,在第一种语法中可用来声明变量并设置变量的属性([rix]即为变量的属性),在第二种语法中可用来显示shell函数。若不加上任何参数,则会显示全部的shell变量与函数(与执行set指令的效果相同)。
语法:declare [+/-][rxi][变量名称=设置值] 或 declare -f
-
+/- "-"可用来指定变量的属性,"+"则是取消变量所设的属性。
-
-f 仅显示函数。
-
-r 将变量设置为只读。
-
-x 指定的变量会成为环境变量,可供shell以外的程序来使用。
-
-i [设置值]可以是数值,字符串或运算式。
声明整数型变量
# declare -i ab //声明整数型变量
# ab=56 //改变变量内容
# echo $ab //显示变量内容
56
改变变量属性
# declare -i ef //声明整数型变量
# ef=1 //变量赋值(整数值)
# echo $ef //显示变量内容
1
# ef="wer" //变量赋值(文本值)
# echo $ef
0
# declare +i ef //取消变量属性
# ef="wer"
# echo $ef
wer
设置变量只读
# declare -r ab //设置变量为只读
# ab=88 //改变变量内容
-bash: ab: 只读变量
# echo $ab //显示变量内容
56
声明数组变量
# declare -a cd='([0]="a" [1]="b" [2]="c")' //声明数组变量
# echo ${cd[1]}
b //显示变量内容
# echo ${cd[@]} //显示整个数组变量内容
a b c
显示函数
# declare -f
command_not_found_handle ()
{ if [ -x /usr/lib/command-not-found ]; then/usr/bin/python /usr/lib/command-not-found -- $1;return $?;elseif [ -x /usr/share/command-not-found ]; then/usr/bin/python /usr/share/command-not-found -- $1;return $?;elsereturn 127;fi;fi
}
read 从键盘读入变量值
-
read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量
-
格式:read -参数 变量名
-
参数
-
-p “提示语句:” 屏幕打印出一行提示语句。
-
-n数字:当输入的字符数目达到预定数目时,自动退出,并将输入的数据赋值给变量,如:-n1 , 只要接受到一个字符就退出。只要按下一个字符进行回答,read命令立即接受输入并将其传给变量。无需按回车键
-
-t 等待时间 :计时输入,使用read命令存在着潜在危险。脚本很可能会停下来一直等待用户的输入。如果无论是否输入数据脚本都必须继续执行,那么可以使用-t选项指定一个计时器。-t选项指定read命令等待输入的秒数。当计时满时,read命令返回一个非零退出状态
-
-s : 关闭回显,使read命令中输入的数据不显示在监视器上(实际上,数据是显示的,只是read命令将文本颜色设置成与背景相同的颜色)
-
常用格式:
-
read 变量名
read -p "提示信息:" 变量名
-
例:
[root@server ~]# read -p "Enter Numbers: " num
Enter Numbers: 9527
[root@server ~]# echo $num
9527
[root@server ~]# read -t 3 n1 # 不要输入内容,等待3秒后自动结束输入
[root@server ~]# read -s -p "Enter your password: " passw
Enter your password: [root@server ~]# echo $passw
123456
[root@server ~]# echo $REPLY
[root@server ~]# read
100
[root@server ~]# echo $REPLY # 当输入时没有指定变量接收,会默认存储到REPLY变量中
100
# 一次性输入多个变量的值
[root@server ~]# read t1 t2
12 35
[root@server ~]# echo $t1 $t2
12 35
-
面试题:总结4中赋值方式
1.直接赋值:name="li si"
2.read命令: read name
3.使用位置参数($1 $2 $3…) : name=$1
4.命令输入:name=$(whoami) (命令返回值赋值)
shift命令: 剔除
- 当Shell程序不知道其个数时,可以把所有参数一起赋值给变量$*。
- 若用户要求Shell在不知道位置变量个数的情况下,还能逐个的把参数一一处理。
- 在 shift命令执行前变量的值在shift命令执行后就不可用了。
示例如下:
echo "参数个数$#“
echo "所有参数$*"
shift #默认剔除一个
echo "参数个数$#“
echo "所有参数$*"
shift 3
echo "参数个数$#“
echo "所有参数$*"
for i in 1 3 4;douseradd $1shift
done
只读变量(readonly)
- 将变量配置成为 readonly 类型,该变量不可被更改内容,也不能 unset -
定义方法:
- 方法一: readonly [-fap] [变量定义] -f 定义只读函数 -a 定义只读数组变量 -p 显示系统中全部的只读变量列表 变量
- 方法二: declare –r 变量定义
取消变量 unset 选项:-f 取消的是函数 -v 取消的是变量 如果没有指选项,首先尝试取消变量,如果失败尝试取消函数。
unset name注意:Some variables cannot be unset; also see `readonly'.只读变量不能取消。
只读变量:值不能被修改;不能取消