变量和引用
变量:程序设计语言中的一个可以变化的量,当然,可以变化的是变量的值。变量在几乎所有的程序设计语言中都有定义,并且其涵义也大同小异。从本质上讲,变量就是在程序中保存用户数据的一块内存空间,而变量名就是这块内存空间的地址。
在程序的执行过程中,保存数据的内存空间的内容可能会不断地发生变化,但是,代表内存地址的变量名却保持不变。
变量的命名
在 s h e l l shell shell中,变量名可以由字母、数字或者下划线组成,并且只能以字母或者下划线开头
在 s h e l l shell shell语言中,变量名的大小写是敏感的,因此,大小写不同的两个变量名并不代表同一变量
变量的类型
-
根据变量类型确定的时间,可以将程序设计语言分为两类,分别是静态类型语言和动态类型语言。
静态类型语言:在程序的编译期间就确定变量类型的语言,例如 J A V A 、 C + + JAVA、C++ JAVA、C++和 P A S C A L PASCAL PASCAL
动态类型语言:在程序执行过程中才确定变量的数据类型的语言,如 V B S c r i p t VBScript VBScript、 P H P PHP PHP、 P y t h o n Python Python -
根据是否强制要求类型定义,可以将程序设计语言分为强类型语言和弱类型语言。
强类型语言:要求用户在定义变量时必须明确指定其数据类型,如 J a v a 、 C + + Java、C++ Java、C++
弱类型语言:不要求用户明确指定变量的数据类型,如 V B S c r i p t VBScript VBScript
s h e l l shell shell是一种动态类型语言和弱类型语言,即在 s h e l l shell shell中,变量的数据类型无需显示地声明,变量地数据类型会根据不同的操作有所变化。准确地讲, s h e l l shell shell中的变量是不分数据类型的,统一地按照字符串存储。
例1: s h e l l shell shell变量的数据类型
#! /bin/bash
#定义变量下x,并且赋值为123
x=123
#变量x加1
let "x += 1"
#输出变量x的值
echo "x = $x"
#显示空行
echo
#替换x中的1为abc,并且将值赋给变量y
y=${x/1/abc}
#输出变量y的值
echo "y = $y"
#声明变量y
declare -i y
#输出变量y的值
echo "y = $y"
#变量y的值加1
let "y += 1"
#输出变量y的值
echo "y = $y"
#显示空行
echo
#将字符串赋给变量z
z=abc22
#输出变量z的值
echo "z = $z"
#替换变量z中的abc为数字11,并且将值赋给变量m
m=${z/abc/11}
#输出变量m的值
echo "m = $m"
#变量m加1
let "m += 1"
#输出变量m的值
echo "m = $m"
echo
#将空串赋给变量n
n=""
#输出变量n的值
echo "n = $n"
#变量n加1
let "n += 1"
echo "n = $n"
echo
#输出变量p的值
echo "p = $p"
#变量p加1
let "p += 1"
echo "p = $p"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-1.sh
x = 124
y = abc24
y = abc24
y = 1
z = abc22
m = 1122
m = 1123
n =
n = 1
p =
p = 1
为了执行加法运算, s h e l l shell shell会自动进行数据类型的转换,如果遇到含有非数字的字符串,则该字符串将被转换成整数0
变量的定义
在 s h e l l shell shell中,通常情况下用户可以直接使用变量,无需先进行定义,当用户第一次使用某个变量名时,实际上就同时定义了这个变量,在变量的作用域内,用户都可以使用该变量。
例2:直接使用变量定义变量
#! /bin/bash
#定义变量a
a=1
#定义变量b
b="hello"
# 定义变量c
c="hello world"
通过以上方式可以非常方便地定义变量,但是,对于变量的某些属性却不容易控制,例如,变量的类型和读写属性等。为了更好地控制变量地相关属性, b a s h bash bash提供了一个名称为 d e c l a r e declare declare的命令来声明变量,该命令的基本语法如下:
declare attribute variable
其中, a t t r i b u t e attribute attribute表示变量的属性,常用属性如下:
-
p
p
p:显示所有变量的值
-
i
i
i:将变量定义为整数。在之后就可以直接对表达式求值,结果只能是整数。如果求值失败或者不是整数,就设置为0
-
r
r
r:将变量声明为只读变量。但这没有必要。所有变量都不必显示定义就可以用做数组
-
f
f
f:显示所有自定义函数,包括名称和函数体
-
x
x
x:将变量设置成环境变量,这样在随后的脚本和程序中可以使用
参数variable表示变量名称
d e c l a r e declare declare命令又写做 t y p e s e t typeset typeset
例3:使用不同的方法声明变量
#! /bin/bash
#定义变量x,并将一个算术式赋给它
x=6/3
echo "$x"
#定义变量x为整数
declare -i x
echo "$x"
#将算术式赋给变量x
x=6/3
echo "$x"
#将字符串赋给变量x
x=hello
echo "$x"
#将浮点数赋给变量x
x=3.14
echo "$x"
#取消变量x的整数属性
declare +i x
#重新将算术式赋给变量x
x=6/3
echo "$x"
#求表达式的值
x=$[6/3]
echo "$x"
#求表达式的值
x=$((6/3))
echo "$x"
#声明只读变量x
declare -r x
echo "$x"
#尝试为只读变量赋值
x=5
echo "$x"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-3.sh
6/3
6/3
2
0
./ex3-3.sh: line 15: 3.14: syntax error: invalid arithmetic operator (error token is ".14")
0
6/3
2
2
2
./ex3-3.sh: line 32: x: readonly variable
2
因为 b a s h bash bash并不内置对浮点数的支持,所以得到了上图结果中的第一个错误;第二个错误是因为加了只读权限,尝试修改便会报错
变量和引号
在shell编程中,正确理解引号的作用非常重要。 s h e l l shell shell语言中一共有三种引号,分别为单引号(’’)、双引号("")和反引号(``)。这3种引号的作用是不同的:
- 其中单引号括起来的字符都作为普通字符出现;
- 由双引号括起来的字符,除“$”、“\”、“’”和“"”这几个字符仍是特殊字符并保留其特殊功能外,其余字符仍作为普通字符对待;
- 由反引号括起来的字串被 s h e l l shell shell解释为命令,在执行时, s h e l l shell shell首先执行该命令,并以它的标准输出结果取代整个反引号部分
例4:反引号的使用
#! /bin/bash
#输出当前目录
echo "current directory is `pwd`"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# chmod +x ex3-4.sh
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-4.sh
current directory is /home/ubuntu/shell
变量的作用域
与其他程序设计语言一样, s h e l l shell shell中的变量也分为全局变量和局部变量两种。
全局变量
在 s h e l l shell shell语言中,全局变量是使用范围较大的变量,它不仅限于某个局部使用。在 s h e l l shell shell语言中,全局变量可以在脚本中定义,也可以在某个函数中定义。在脚本中定义的变量都是全局变量,其作用域为从被定义的地方开始,一直到 s h e l l shell shell脚本结束或者被显示的删除
例5:使用全局变量
#! /bin/bash
#定义函数
func()
{
echo "$v1"
#修改变量的值
v1=200
}
#在脚本中定义全局变量x
v1=100
#调用函数
func
echo "$v1"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-5.sh
100
200
除了在脚本中定义全局变量之外,在函数内部定义的默认情况下也是全局变量,其作用域为从函数被调用时执行变量的定义的地方开始,一直到 s h e l l shell shell脚本结束或者被显示地删除为止
例6:函数内部定义全局变量
#! /bin/bash
func()
{
v2=200
}
#调用函数
func
echo "$v2"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# chmod +x ex3-6.sh
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-6.sh
200
函数的参数是局部变量
局部变量
在 s h e l l shell shell中,通过关键字 l o c a l local local定义局部变量,同时,上述提到的函数参数也是局部变量
例7:使用 l o c a l local local关键字定义局部变量
#! /bin/bash
func()
{
#使用local关键字定义局部变量
local v2=200
}
#调用函数
func
echo "$v2"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-7.sh
由于使用了 l o c a l local local来定义 v 2 v2 v2变量,所以在函数外部就访问不到 v 2 v2 v2的值,因此得到一个空值。
如果用户在函数外面定义了一个全局变量,同时在某个函数内部定义又存在相同名称的局部变量,而在调用该函数时,函数内部的局部变量会屏蔽函数外部定义的全局变量。也就是说,在出现同名的情况下,函数内部的局部变量会优先被使用
例8:全局变量与局部变量
#! /bin/bash
func()
{
#输出全局变量v1的值
echo "global variable v1 is $v1"
#定义局部变量v1的值
local v1=2
#输出局部变量v1的值
echo "local variable v1 is $v1"
}
#定义全局变量v1
v1=1
#调用函数
func
#输出全局变量v1的值
echo "global variable v1 is $v1"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-8.sh
global variable v1 is 1
local variable v1 is 2
global variable v1 is 1
小 t i p tip tip: s h e l l shell shell变量中的符号 “ " 表 示 取 变 量 的 值 。 只 有 在 取 值 的 时 候 使 用 , 定 义 和 赋 值 时 无 需 使 用 符 号 " "表示取变量的值。只有在取值的时候使用,定义和赋值时无需使用符号" "表示取变量的值。只有在取值的时候使用,定义和赋值时无需使用符号"”。另外, s h e l l shell shell中变量的原型实际为 v a r , 而 常 用 的 书 写 形 式 {var},而常用的书写形式 var,而常用的书写形式var$只是一个简写。在某些情况下,使用简写会导致程序级错误
系统变量
s h e l l shell shell语言的系统变量主要在对参数判断和命令返回值判断时使用,包括脚本和函数的参数,以及脚本和函数的返回值。 s h e l l shell shell语言中的系统变量并不多,但是十分有用,特别是在做一些参数检测的时候
shell中常见的系统变量
变量名 | 说明 |
---|---|
$ n n n | 表示传递给脚本的第n个参数,例如$1表示第1个参数,$2表示第二个参数… |
$# | 命令行参数的个数 |
$0 | 当前脚本的名称 |
$ ? ? ? | 前一个命令或者函数的返回状态码 |
$ ∗ * ∗ | 以”参数1 参数2 参数3…“的形式返回所有参数的值 |
$ @ @ @ | 以”参数1“ ”参数2“ ”参数3“…的形式返回参数的值 |
$$ | 返回本进程的进程 I D ID ID |
例9:使用系统变量
#! /bin/bash
#输出脚本参数的个数
echo "the number of parameters is $#"
#输出上一个命令的状态码
echo "the return code of last command is $?"
#输出脚本名称
echo "the script name is $0"
#输出所有的参数
echo "the parameters are $*"
#输出其中的几个参数
echo "\$1=$1; \$2=$2; \$11=${11}" #注意:此处不能写成$11,不然会被误认为是$1变量加上一个1
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-9.sh a b c d e f g h i j k l m n
the number of parameters is 14
the return code of last command is 0
the script name is ./ex3-9.sh
the parameters are a b c d e f g h i j k l m n
$1=a; $2=b; $11=k
为了能够使 s h e l l shell shell正确的知道哪些是变量名,用户可以使用大括号来界定变量名
环境变量
s h e l l shell shell的环境变量是所有 s h e l l shell shell程序中都可以使用的变量
$shell$中常见的环境变量
变量名 | 说明 |
---|---|
P A T H PATH PATH | 命令搜索路径,以冒号为分隔符。注意与windows下不同的是,当前目录不在系统路径中 |
H O M E HOME HOME | 用户主目录的路径名,是cd命令的默认参数 |
C O L U M N S COLUMNS COLUMNS | 定义了命令编辑模式下可使用命令行的长度 |
H I S T F I L E HISTFILE HISTFILE | 命令历史文件 |
H I S T S I Z E HISTSIZE HISTSIZE | 命令历史文件中最多可包含的命令条数 |
H I S T F I L E S I Z E HISTFILESIZE HISTFILESIZE | 命令历史文件中包含的最大行数 |
I F S IFS IFS | 定义 s h e l l shell shell使用的分隔符 |
L O G N A M E LOGNAME LOGNAME | 当前的登录名 |
S H E L L SHELL SHELL | s h e l l shell shell的全路径名 |
T E R M TERM TERM | 终端类型 |
T M O U T TMOUT TMOUT | s h e l l shell shell自动退出的时间,单位为秒,若设0则禁止 s h e l l shell shell自动退出 |
P W D PWD PWD | 当前工作目录 |
可以使用 s e t set set命令列出所有的环境变量:
root@VM-0-2-ubuntu:/home/ubuntu/shell# set | more
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:p
rogcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="4" [2]="19" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
BASH_VERSION='4.4.19(1)-release'
COLUMNS=133
DIRSTACK=()
EUID=0
GROUPS=()
HISTFILE=/root/.bash_history
HISTFILESIZE=2000
HISTSIZE=3000
HISTTIMEFORMAT='%F %T '
HOME=/root
HOSTNAME=VM-0-2-ubuntu
HOSTTYPE=x86_64
IFS=$' \t\n'
LANG=en_US.utf8
LESSCLOSE='/usr/bin/lesspipe %s %s'
LESSOPEN='| /usr/bin/lesspipe %s'
LINES=45
LOGNAME=root
...
例10:使用环境变量
#! /bin/bash
#输出命令搜索路径
echo "commands path is $PATH"
#输出当前的登录名
echo "current login name is $LOGNAME"
#输出当前用户的主目录
echo "current user's name is $HOME"
#输出当前的shell
echo "current shell is $SHELL"
#输出当前工作目录
echo "current path is $PWD"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-10.sh
commands path is /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
current login name is root
current user's name is /root
current shell is /bin/bash
current path is /home/ubuntu/shell
变量赋值和清空
变量赋值
在 s h e l l shell shell语言中,通常情况下变量并不需要专门的定义和初始化语言。一个没有初始化的 s h e l l shell shell变量被认为是一个空字符串。用户可以通过变量的赋值操作来完成变量的声明并赋予一个特定的值。并且可以通过赋值语句为一个变量多次赋值,以改变其值
在 s h e l l shell shell中,变量的赋值可以用如下语法:
variable_name=value
其中, v a r i a b l e variable variable_ n a m e name name表示变量名, v a l u e value value表示将要赋给变量的值。一般情况下, s h e l l shell shell中将所有普通变量的值都看做字符串。如果 v a l u e value value中包含空格、制表符和换行符,则必须用单引号或者双引号将其引起来。双引号中允许变量替换,而单引号中则不允许
中间的等于号称为赋值符号,赋值符号的左右两边不能直接跟空格,否则shell会将其视为命令
例11:成功的赋值
v1=10
v2='RedHat Linux'
v3="RedHat Linux $HOSTTYPE"
v4=12345
引用变量的值
通过在变量名前加上“$”来获取变量的值。
例:引用 s h e l l shell shell变量
#! /bin/bash
v1=10
v2='RedHat Linux'
v3="RedHat Linux $HOSTTYPE"
v4=12345
#输出变量v1的值
echo "$v1"
#输出变量v2的值
echo "$v2"
#输出变量v3的值
echo "$v3"
#输出变量v4的值
echo "$v4"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# chmod +x ex3-11.sh
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-11.sh
10
RedHat Linux
RedHat Linux x86_64
12345
在
s
h
e
l
l
shell
shell中,字符串是可以直接连接在一起的。
测试一下:将上述的输出v4变量的值改为
echo "$v4abc"
测试结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-11.sh
10
RedHat Linux
RedHat Linux x86_64
结果发现输出了一个空字符串,得到这个结果其实也不难解释,就像之前提到过的一样,因为 s h e l l shell shell不能正确识别出$v4这个变量,所以为了防止出现这样的结果,最好用大括号来将变量名进行一个明确的确定:
echo "${v4}abc"
测试:
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-11.sh
10
RedHat Linux
RedHat Linux x86_64
12345abc
清除变量
当 s h e l l shell shell不需要某个变量时,可以将其清除。当变量被清除后,其所代表的值也会消失。清除变量使用 u n s e t unset unset语句,其语法如下:
unset variable_name
例:使用 u n s e t unset unset清除变量
#! /bin/bash
v1="Hello world"
echo "$v1"
unset v1 #清除变量v1
echo "the value of v1 has been reset"
echo "$v1"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-12.sh
Hello world
the value of v1 has been reset
因为变量v1的值被清楚了,所以最后一行的 e c h o echo echo仅仅输出了空值
引用和替换
引用
所谓引用,是指将字符串用引用符号包括起来,以防止其中的特殊字符被 s h e l l shell shell解释为其他涵义。特殊字符是指除了字面意思之外还可以解释为其他意思的字符。例如。在 s h e l l shell shell中不仅可以表示美元符号,还可以用于获取某个变量的值,即变量替换。"*"可以用作通配符使用
例:星号通配符的使用
root@VM-0-2-ubuntu:/home/ubuntu/shell# ll ex*
-rwxr--r-- 1 root root 135 Mar 5 23:14 ex1-2.sh*
-rwxr-xr-x 1 root root 46 Mar 4 15:50 ex1-3.sh*
-rwxr--r-- 1 root root 592 Mar 4 15:49 ex1-4.sh*
在当前ll命令中,参数 e x ∗ ex* ex∗表示列出以 e x ex ex开头的文件。但如果给 e x ∗ ex* ex∗加上引号令其被引用,则其涵义会发生变化
root@VM-0-2-ubuntu:/home/ubuntu/shell# ll "ex*"
ls: cannot access 'ex*': No such file or directory
用双引号将其引用起来,则 e x ex ex*仅表达其字面意义,即查询文件名为 e x ex ex*的文件,所以,给出没有该文件或目录的信息
在shell中,共有4种引用符号:
常用引用符号
引用符号 | 说明 |
---|---|
双引号 | 除美元符号、单引号、反引号、反斜线之外,其他所有字符都将保持字面意义 |
单引号 | 所有的字符都将保持字面意义 |
反引号 | 反引号中的字符串将被解释为s h e l l hell hell命令 |
反斜线 | 转义字符,屏蔽后的字符的特殊意义 |
全引用
被单引号引用起来的所有字符都将被解释为普通的字符,因此,这种方式被称为全引用
例:全引用
#! /bin/bash
v1="chunxiao"
echo 'Hello, $v1'
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# chmod +x ex3-14.sh
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-14.sh
Hello, $v1
部分引用
被双引号引用起来的字符除美元符号、单引号、反引号、反斜线之外,其他所有字符都将保持字面意义,这称为部分引用。也就是说,在部分引用中,"$"、"`"、""仍然具有特殊意义
例:部分引用
#! /bin/bash
v1="chunxiao"
echo "Hello, $v1"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# chmod +x ex3-15.sh
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-15.sh
Hello, chunxiao
命令替换
所谓命令替换,是指在 s h e l l shell shell程序中,将某个 s h e l l shell shell的命令的执行结果赋给某个变量。在 b a s h bash bash中,有两种语法可以进行命令替换,分别使用反引号和圆括号,如下:
`shell_command`
$(shell_command)
例:反引号使用
#! /bin/bash
#变量替换
v1=`pwd`
echo "current directory is $v1"
结果:
root@VM-0-2-ubuntu:/home/ubuntu/shell# chmod +x ex3-16.sh
root@VM-0-2-ubuntu:/home/ubuntu/shell# ./ex3-16.sh
current directory is /home/ubuntu/shell
shell会将反引号中的字符串当作 s h e l l shell shell命令。如果输入了错误的命令,则会出现“ c o m m a n d n o t f o u n d command not found commandnotfound”的错误提示
也可以使用圆括号进行命令替换:
#! /bin/bash
#变量替换
v1=$(pwd)
echo "current directory is $v1"
结果与上述一致
转义
顾名思义,转义的作用是转换某些特殊字符的意义。转义使用反斜线表示,当反斜线后面的一个字符具有特殊的意义时,反斜线将屏蔽该字符的特殊意义,使得shell按照该字符的字面意义来解释
例:转义
root@VM-0-2-ubuntu:/home/ubuntu/shell# echo $SHELL
/bin/bash
root@VM-0-2-ubuntu:/home/ubuntu/shell# echo \$SHELL
$SHELL #使用了反斜线,$失去了其特殊的作用