shell 脚本编程之变量

简介

Shell 是指一种命令行解释器,为用户和操作系统之间进行通信提供一种接口,它接受来自用户的命令,并将其转换成一系列的系统调用送到内核执行,并将结果输出给用户。Shell 不仅是一种解释器,还是一种编程工具,脚本语言。Shell 有很多种,本系列文章只介绍 Bash Shell。

变量命名

Shell 的变量命名和大多数语言一样,由字母,数字和下划线组成,第一个字符只能是字母或下划线。Shell 变量区分大小写,不能使用系统关键字。

变量创建、使用和回收

  • Shell 变量是“弱类型”变量,同个变量可以赋不同类型的值
  • 变量不需要定义,也不需要先声明再使用,第一次赋值就是声明变量
[root@localhost ~]# name="lin"
[root@localhost ~]# echo $name

变量赋值直接用一个等号把变量和值关联起来,中间不能有空格;赋字符串值时可以没有引号,也可以使用单引号和双引号,但如果是把变量赋给变量的话,那必须使用双引号,因为单引号解析不了 符号,取值时则需要。

[root@localhost ~]# name=lin
[root@localhost ~]# echo $name
[root@localhost ~]# name='jin'
[root@localhost ~]# echo $name
[root@localhost ~]# name="xin"
[root@localhost ~]# echo $name
[root@localhost ~]# name=1
[root@localhost ~]# name_2=$name
[root@localhost ~]# name_3="$name"
[root@localhost ~]# name_4='$name'
[root@localhost ~]# echo $name $name_2 $name_3 $name_4

最后一个命令的输出是 1 1 1 $name,$name_2 和 $name_3 可以直接取到 $name 的值,但 $name_4 则取不到,它得到的值是字符串 $name,所以它的值就是 $name 而不是 1。
如果要回收变量,使用 unset 命令来取消变量,它的内存也会被释放,函数也可以取消。

[root@localhost ~]# name=true
[root@localhost ~]# echo $name
[root@localhost ~]# unset name
[root@localhost ~]# echo $name
[root@localhost ~]# foo()
[root@localhost ~]> {
[root@localhost ~]>   echo 'hello world'
[root@localhost ~]> }
[root@localhost ~]# foo
[root@localhost ~]# unset foo
[root@localhost ~]# foo

第一次输出变量 name 的值是输出 true,第二次输出什么都没有,因为 name 已经被回收了;第一次调用 foo 函数时会打印出 ‘hello world’,第二次调用会提示命令不存在,因为函数 foo 已经被回收了。
变量不需要先声明再使用,如果变量未声明(即没赋过值)就开始使用,那得到的值会是空的,但不会报错。如果想要提高脚本的严谨性,可以强制要求变量必须先声明再使用,如果使用未声明的变量则会报错。

[root@localhost ~]# echo $undefined_var
[root@localhost ~]# shopt -s -o nounset
[root@localhost ~]# echo $undefined_var

第一个命令什么也没输出,但不会报错;第二个命令把当前 shell 环境设置成变量必须先声明再使用;第三个命令就报错了,因为变未声明,不能取它的值。

变量的作用域

变量只作用在它的“命名空间”中,默认命名空间是指当前 shell 或当前脚本文件,不同 shell 之间以及不同脚本之间的变量是互不干扰的。在当前命名空间声明的变量,其作用域就是整个命名空间,所以在函数内部的变量和函数外部的变量,其作用域是一样的;如果要在函数内使用局限于函数内部的变量,可手动加上 local 关键字。
learn_var1.sh

#!/bin/bash
name='lin'
foo()
{
    name='jin'
    echo name in function is $name
}
foo
echo "name out of function is" $name
exit 0

执行结果

name in function is jin
name out of function is jin

learn_var2.sh

#!/bin/bash
name='john'
foo()
{
    local name=marry
    echo name in function is $name
}
foo
echo name out of function is $name
exit 0

执行结果

name in function is marry
name out of function is john

第一个脚本在函数内部和外部输出的结果是一样的,这是因为函数内部修改了变量的值,修改的是在函数外面定义的变量 name;而第二个脚本则输出不同的结果,因为函数内部使用 lcoal 关键字声明了一个只属于自己的变量,与外面的变量相互独立。另外,两个脚本使用了相同的变量名和函数名,但不会出现相互干扰的情况,因为这是两个作用域。
变量分为两种,环境变量和局部变量。局部变量只能在当前 shell 中使用,因为这是它的作用域,也就是说局部变量只在其作用域内工作;环境变量不仅可以在当前 shell 使用,还可以在继承自当前 shell 的子 shell 使用。变量默认是局部变量,如果要使其成为环境变量,可以使用 export 命令将其导出。

[root@localhost ~]# name=july
[root@localhost ~]# echo $name
[root@localhost ~]# bash
[root@localhost ~]# echo $name
[root@localhost ~]# exit
[root@localhost ~]# export name
[root@localhost ~]# bash
[root@localhost ~]# echo $name

在当前 shell 中定义变量 name 并输出它的值,得到字符串 july;然后使用 bash 会打开一个新的 shell,这个 shell 是当前 shell 的子 shell,在子 shell 中输出变量 name 的值,得到一个空值。使用 exit 命令会返回到父 shell,在父 shell 中将变量 name 导出,再重新打开一个子 shell,输出变量 name 的值发现输出 july,说明此时变量已经成为环境变量了。

数组

shell 只支持一维数组,数组的索引从 0 开始,数组的大小不是固定的,可以随时扩展数组,也可以跳跃式地给元素赋值。

定义数组

使用 declare 关键字加上命令 -a 就可以声明一个数组变量,默认数组的长度为 0。如果在声明的时候就已经给数组初始化一些元素,则使用一对小括号来赋值,数组元素之间用空格隔开;声明时初始化可以省略 declare 关键字。

#!/bin/bash
declare -a arr
arr[0]=hello
arr[1]=2
arr[2]=true
echo ${arr[@]}

unset arr
declare -a arr=('good' 1011 'job')
echo ${arr[@]}

unset arr
arr=([1]='lin' [3]='jin' [5]='xin')
echo ${arr[@]}

执行结果

hello 2 true
good 1011 job
lin jin xin
取数组元素

取数组元素直接使用数组加上索引即可,取变量名的标准写法是 ${变量名},一般 {} 可以省略,但在某些情况下省略会出问题,比如取数组元素的时候,$arr[0] 的结果是取数组的值再连接字符串 [0]
* 取数组某个下标元素 ${array[index]}
* 取数组所有元素(返回以空格隔开的元素值) ${array[@]}
* 取数组所有元素(返回所有元素连接起来的字符串) ${array[*]}
* 取数组长度 ${#array[@]} 或 ${#array[*]}
* 使用 @ 和 * 都可以获取数组的所有元素,返回的结果”类型“虽然不一样,但值都是所有元素拼接起来,中间用空格隔开
* # 不仅可以取数组的长度,还可以取字符串的长度
* $array 等价于 ${array[0]}

arr=(100 [1]=lin [3]=3.14 [4]=good)
echo ${arr}
echo ${arr[0]}
echo ${arr[1]}
echo ${arr[3]}
echo ${arr[@]}
echo ${arr[*]}
echo ${#arr[@]}
echo ${#arr[4]}
str=good
echo ${#str}

执行结果

100
100
lin
3.14
100 lin 3.14 good
100 lin 3.14 good
4
4
4
数组截取

可以使用 ${array[@]:start:len} 来取数组的多个元素,返回一个拼接后的字符串,取值的区间是 [start,start+len]。同样该方法也适用于字符串,用于取子字符串。

arr=(1 2 3 4 5)
echo ${arr[@]:1:3}
arr[5]=hello
echo ${arr[5]:2:2}
str=good
echo ${str:1:2}

执行结果

2 3 4
ll
oo
连接数组

可以把多个数组连接成一个新的数组,连接的方法是使用数组的初始化方法,即 array=(element1 element2),其实是创建一个新的数组,然后把原来的数组的值赋给新数组。

arr1=(10 20 0)
arr2=(100 200 300)
arr3=(${arr1[@]} ${arr2[@]})
arr4=(${arr1[*]} ${arr2[*]})
echo ${arr3[@]}
echo ${arr4[@]}
echo ${#arr3[*]}
echo ${#arr4[*]}
echo ${arr4[5]}

执行结果

10 20 30 100 200 300
10 20 30 100 200 300
6
6
300
替换数组元素

替换元素最简单的方法就是给某个下标的元素重新赋值,还有一种替换方法,不需要知道元素的下标而根据元素的值直接替换。

arr=(hi good)
arr[1]=bad
arr=(${arr[@]/hi/hello})
echo ${arr[@]}
arr=(${arr[*]/hello/你好})
echo ${arr[@]}

执行结果

hello bad
你好 bad
取消数组元素

取消数组元素和取消其它变量一样,使用 unset 关键字,如果要取消整个数组,则使用 unset 加上数组名。

arr=(1 2 3 4)
unset arr[0]
echo $arr
echo ${arr[@]}
unset arr
echo ${arr[@]}

执行结果

1: 
2: 2 3 4
3:

第一个输出的结果为空,因为 $arr 取的是 arr 的第一个元素,即 arr[0],而 arr[0] 被取消了,所以输出空。第三个输出也是空,因为整个数组都被取消了。

特殊变量

位置参数

脚本执行时可带一些参数,参数的个数是不定的,如何取到这些不定的参数,就需要使用位置参数变量了。使用 $n(n为数字) 来取到脚本运行时的参数,$0 为脚本本身的名称,$1 为第一个参数,依此类推;当参数位置大于 9 时,需要使用 {} 括起来,比如取第 10 个位置(参数) 的写法是 ${10}。使用 $# 获取参数的个数,不包括 $0,也就是不包括脚本本身;$@ 或 $* 来获取所有参数,两样不包括 $0。如果取一个不存在参数的位置,则取到的是空值。

echo "the script's name is : $0"
echo "the first parameter is : $1"
echo "the second parameter is : $2"
echo "the third parameter is : $3"
echo "all the parameter is : $@"
echo "the number of parameter is : $#"

执行结果1

[root@localhost ~]#  ./learn_special_var.sh -path /bin/sh/var -language shell
the script's name is : ./learn_special_var.sh
the first parameter is : -path
the second parameter is : /bin/sh/var
the third parameter is : -language
all the parameter is : -path /bin/sh/var -language shell
the number of parameter is : 4

执行结果2

[root@localhost ~]#  ./learn_special_var.sh -language shell
the script's name is : ./learn_special_var.sh
the first parameter is : -language
the second parameter is : shell
the third parameter is :
all the parameter is : -language shell
the number of parameter is : 2
脚本或命令返回值

每个脚本或命令都会有一个返回值,shell 认为返回 0 才表示脚本正常执行。如果输入了一个不存在的命令,则会返回 127;ping 主机不能时返回 1。 ?使 ? 来取到脚本或命令返回值。如果我们的脚本没有显式地写返回值,则默认返回 0。

[ljx@localhost ~]$ ifconfi
bash: ifconfi: command not found
[ljx@localhost ~]$ echo $?
127

[ljx@localhost ~]$ ./learn_special_var.sh
the script's name is : ./learn_special_var.sh
the first parameter is :
the second parameter is :
the third parameter is :
all the parameter is :
the number of parameter is : 0
[ljx@localhost ~]$ echo $?
0

系统环境变量

bash 默认预定义了很多系统环境变量,下面列举一些

变量名含义
$BASH系统安装 bash shell 的全路径
$BASH_VERSION
$CDPATH
$EUID
$FUNCNAME
$HISTCMD
$HISTFILE
$HISTFILESIZE

只读变量

如果声明的时候在前面加上 readonly 关键字,则该变量就是只读变量。只读变量只能在声明时赋一次值,如果声明时不赋值,那它的值就是空,后面不能再修改它的值。另外,只读变量不能被取消。

[ljx@localhost ~]$ readonly ro=10
[ljx@localhost ~]$ echo $ro
10
[ljx@localhost ~]$ ro=100
bash: ro: readonly variable
[ljx@localhost ~]$ unset ro
bash: unset: ro: cannot unset: readonly variable
[ljx@localhost ~]$ readonly rovar
[ljx@localhost ~]$ echo $rovar
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值