变量与数据
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"
可以看到带引号的变量输出会包含换行。
数组
数组或者序列又叫索引数组(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命令的常用格式表:
格式符号 | 含义 | 示例 |
---|---|---|
%Y | 年 | 2032 |
%m | 月 | 01..12 |
%d | 日 | 01 |
%H | 时 | 00..23 |
%M | 分 | 00..59 |
%S | 秒 | 00..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'