跳到主要内容

变量与数据

bash 脚本作为脚本语言的一种也有其特定的语法结构,熟练掌握常用的基本语法是编写脚本的基础。

变量

变量名

bash中变量名由a-z A-Z 0-9_ 组成,自定义变量不能以数字开头,而纯数字的变量用于位置传参。

变量类型

变量按照作用域可分为全局变量和局部变量,局部变量存在于函数中,通过 local 关键字定义,如果是在函数外使用 local 则会引起语法错误。需要注意如果不加 local , 默认表示全局变量,即使是在函数里面定义也一样,所以通常我建议函数内一律定义局部变量,全局变量只在函数外定义,这样可以避免变量冲突带来的各种麻烦,特别是shell这种即使变量冲突他也不会报错的情况下,如果全局变量满天飞,指不定在哪个地方变量值就被莫名其妙改写,如果不通过外部工具检查,靠人肉调试发现这种隐匿的BUG就会特别X疼。

变量按照其可读写状态又可分为可读写变量和只读变量,只读变量通过 readonly 关键字定义,当一个只读变量被尝试重新赋值的时候会引起报错。

变量赋值

定义一个变量的方式:

# 全局变量
k1=v1
func_a() {
    # 局部变量
    local k1=v1
}

# 只读变量
readonly k2=v2

# 使用declare显示声明变量
declare k3=v3

注意等号两边没有空格,如果不小心多了空格会导致空格前后内容被当作命令直接执行。

要取消一个变量值,可以使用unset:

unset k1

注意,只读变量一经定义,就无法使用 unset 取消。

变量引用

通过在变量名前面加$符引用变量,如$k1 ,或者${k1},通常{}可以省略,但是当接收位置传参的时候参数个数超过个位数及大于等于10个的时候,就不能省略,必须使用带有花括号的$12,如果使用$12,该变量的值会被解析成$1和2的组合。示例如下:

echo $k1
echo ${k2}
echo $1
echo ${12}

数据类型

相比其他语言,bash shell的数据类型并不算丰富,但也可以提供数字、字符串、数组、字典等类型。需要注意的是bash并不原生支持浮点数运算,只能借助外部命令完成,也没有严格意义的布尔值类型,布尔运算结果是通过返回值的0和1来表示或者自定义使用数字、字符串来表示。

数字

严格来讲bash中的数字也是字符串,只是在使用时进行了自动转换而已。数字的值可以是整数或者浮点数,默认为十进制,也可以支持其他进制的数。bash原生支持整数,但是如前所说不原生支持浮点数。

num1=6
num2=6.6

字符串

字符串是最常用的类型没有之一,bash可以非常灵活的处理各种各样字符串。

str1=string
str1='string with multi words'

默认情况下,包含空格的字符串需要使用引号括起来,其中引号又有单引号、双引号的差别。在双引号中 $开头的字符串表示一个变量,在引用的时候会被解析,而单引号则不会。

cm=0
echo '神啊,请给我加1$cm厘米'
echo "神啊,请给我加1$cm厘米"

shell中执行以上两行会得到不同的输出。 多行字符串也可以使用单引号或者双引号括起来,需要注意的是输出的时候带引号和不带引号是有差别的。

str1="
a
a b
a b c
"
echo $str1
echo "$str1"

str

可以看到带引号的变量输出会包含换行。

数组

数组或者序列又叫索引数组(indexed array)。数组的作用是将一个系列的元素组织到一个变量中,元素的索引从0开始。bash中的数组和其他语言的数组不太一样,它更像是python中的list。定义数组可以使用下面的方式:

# 一个包含多个元素的数组
arr1=(A B C)
arr1[3]=D
arr1[4]=E
# 或者显示声明一个数组
declare -a arr1

数组的值可以通过下面方式获取到

# 按索引获取单个元素
${arr1[2]}
# 全部元素
${arr1[@]}
# 获取全部索引值
${!arr1[@]}
# 数组长度
${#arr1[@]}

字典

字典本质是一个关联数组(associative array)。你可以理解为将indexed array的index值替换为自定义的值而非默认的数字。 定义一个字典:

# 字典只能用declare -A声明
declare -A dict1
dict1=(
    ['a']=A
    ['b']=B
    ['c']=C
)
dict1[d]=D

获取字典的值:

# 获取指定key的value
echo ${dict1[b]}
# 获取所有value
echo ${dict1[@]}
# 获取所有key
echo ${!dict1[@]}
# 获取字典长度
echo ${#dict1[@]}

日期时间

严格来讲bash中并没有时期时间这样的单独类型,一个日期时间的值也只是带格式的字符串而已,日期时间通过date命令进行获取,支持通过'+FORMAT'参数自定义格式,以下整理了date命令的常用格式表:

格式符号含义示例
%Y2032
%m01..12
%d01
%H00..23
%M00..59
%S00..60
%u星期1..7
%z时区+0800
%s时间戳自1970-01-01 00:00:00以来的秒数
%F组合格式等同于%Y-%m-%d
%T组合格式等同于%H:%M:%S

这里仅是date命令支持地部分格式,完整的格式请参照man date。下面演示一些针对日期时间的基本格式操作:

# 10位时间戳,例如 1661155489
date '+%s'
# 13位时间戳,例如 1661155534689
date '+%s%3N'
# 格式化输出 ,例如 2022-08-22 16:06:50
date '+%F %T'
# 指定时间,格式化成时间戳
date -d '2032-08-22 16:06:50' '+%s'
# 指定时间戳,格式化
date -d '@1976774810' '+%Y%m%d-%H%M%S'