Shell的变量包括用户自定义变量、位置变量、Shell预定义变量及环境变量等。这一节我们来学习自定义变量,剩下的几种变量在接下来的几节中分别学习。
1. 变量命名
Shell自定义变量的命名规则有以下几个:
另外,在Shell实际编程中,变量名应能从名字上看出变量内容的含义,如human_protein、plant_cds等,不建议使用tmp、var1、var_2等没有明显意义的变量名。
2. 变量赋值
Shell变量不需要定义,可以直接赋值,并且Shell是弱类型语言,变量没有整数型、字符型等类型的区分。
Shell变量赋值时,变量名前没有$,后面紧跟等号(=)及变量值,等号两侧不能有空白,这一点与其他语言有较大区别。
[peter@ibi-genome shell]$ plant=fern #变量名前不能有$,=前后不能有空白 [peter@ibi-genome shell]$ plant = fern #若=前有空白,Shell会将变量名解释为命令 bash: plant: command not found... [peter@ibi-genome shell]$ $plant=fern #若变量名前有$,Shell先进行变量替换, 将变量plant替换成其内容fern bash: fern=fern: command not found... [peter@ibi-genome shell]$ plant="seed plant" #如果值里面有空格,需在两侧加引号
命令的执行结果也可以赋值给变量,即命令替换。命令替换有两种方法,反引号(``)或$( ):
[peter@ibi-genome shell]$ current_time=`date` [peter@ibi-genome shell]$ echo $current_time 2017年 05月 02日 星期二 13:26:45 CST [peter@ibi-genome shell]$ current_dir=$(pwd) [peter@ibi-genome shell]$ echo $current_dir /home/peter/shell
变量还可以从标准输入赋值:
[peter@ibi-genome shell]$ read animal #回车后,Shell等待输入 dog [peter@ibi-genome shell]$ echo $animal dog
3. 数组
Bash的数组有以下特点:
数组赋值时可以单独给一个数组元素赋值,也可以将多个值一起赋值给数组:
[peter@ibi-genome shell]$ color[0]=red [peter@ibi-genome shell]$ color=(red green blue)
4. 变量引用
(1)变量直接引用
简单变量直接引用时在变量名前加$即可,如
[peter@ibi-genome shell]$ color=red [peter@ibi-genome shell]$ echo $color red [peter@ibi-genome shell]$ new_color=$color [peter@ibi-genome shell]$ echo $new_color red [peter@ibi-genome shell]$ echo ${#new_color} #变量的长度 3
(2)变量内容修改后引用
①变量内容删除 变量的内容可以使用通配符从头部或尾部删除部分内容。匹配时又分最短匹配和最长匹配两种。
变量设置方式 说明 ${var#expr} 从变量内容前面删除到第一个符合的expr(最短匹配) ${var##expr} 从变量内容前面删除到最后一个符合的expr(最长匹配) ${var%expr} 从变量内容后面删除到最后一个符合的expr(最短匹配) ${var%%expr} 从变量内容后面删除到第一个符合的expr(最长匹配)
如下面的例子:
[peter@ibi-genome shell]$ path=/bin:/usr/bin:/usr/local/bin:/home/peter/bin [peter@ibi-genome shell]$ echo $path /bin:/usr/bin:/usr/local/bin:/home/peter/bin [peter@ibi-genome shell]$ echo ${path#*:} /usr/bin:/usr/local/bin:/home/peter/bin #/bin:/usr/bin:/usr/local/bin:/home/peter/bin(从前面删除到第一个冒号) [peter@ibi-genome shell]$ echo ${path##*:} /home/peter/bin #/bin:/usr/bin:/usr/local/bin:/home/peter/bin(从前面删除到最后一个冒号) [peter@ibi-genome shell]$ echo ${path%:*} /bin:/usr/bin:/usr/local/bin # /bin:/usr/bin:/usr/local/bin:/home/peter/bin(从后面删除到最后一个冒号) [peter@ibi-genome shell]$ echo ${path%%:*} /bin # /bin:/usr/bin:/usr/local/bin:/home/peter/bin(从后面删除到第一个冒号)
②变量内容部分替换 变量值将匹配到的内容替换成指定内容。
变量设置方式 说明 ${var/old_expr/new_expr} 将变量var的内容中第一个old_expr替换成new_expr ${var//old_expr/new_expr} 将变量var的内容中所有的old_expr替换成new_expr
如下面的例子:
[peter@ibi-genome shell]$ echo ${path/bin/BIN} /BIN:/usr/bin:/usr/local/bin:/home/peter/bin #第一个bin被替换 [peter@ibi-genome shell]$ echo ${path//bin/BIN} /BIN:/usr/BIN:/usr/local/BIN:/home/peter/BIN #所有的bin被替换
③变量内容整体替换 根据变量是否赋值和是否为空决定变量被引用的值。
变量设置方式 a没有设置 a为空字符串 a为非空字符串 b=${a-str} b=str b= b=$a b=${a:-str} b=str b=str b=$a b=${a+str} b= b=str b=str b=${a:+str} b= b= b=str b=${a=str} a=str a不变 a不变 b=str b= b=$a b=${a:=str} a=str a=str a不变 b=str b=str b=$a b=${a?str} str => stderr b= b=$a b=${a:?str} str => stderr str => stderr b=$a
上述变量设置方式当中,+和-只影响变量b的值,=还会影响变量a的值,而?会根据变量a的值显示提示信息。上表内容太多,很难记得住,我们只需了解这种变量替换方式,如果写程序遇到这种需求,查一下该表就可以了。
另外,变量b经常跟变量a是同一个变量,也就是用来根据一个变量是否为空然后赋值。
(3)数组引用
数组元素可以单独引用,整个数组也可以一起引用。另外,我们可以方便的引用数组元素的个数或数组元素的长度。
数组引用方式 说明 ${array[i]} 数组array第i个元素 ${array[*]} 或 ${array[@]} 数组array所有的元素 ${#array[i]} 数组array第i个元素的长度 ${#array[*]}、${#array[@]} 或 ${#array} 数组array元素的个数
如:
[peter@ibi-genome shell]$ flower=(lily "Chinese rose" tulip) [peter@ibi-genome shell]$ echo ${flower[1]} Chinese rose [peter@ibi-genome shell]$ echo ${flower[*]} lily Chinese rose tulip [peter@ibi-genome shell]$ echo ${#flower[1]} 12 [peter@ibi-genome shell]$ echo ${#flower[@]} 3
上面的${array[*]}和${array[@]}在使用时有一些区别,使用双引号时,"${array[*]}"扩展成由空格将数组元素连接成的一个字符串,而"${array[@]}"扩展成多个词,每个数组元素是一个词。如果不用双引号,两种方式都扩展成多个词,并且数组元素中的空格也作为词的分隔符。如我们用for循环输出上面的数组:
[peter@ibi-genome shell]$ for i in "${flower[*]}";do echo $i;done lily Chinese rose tulip [peter@ibi-genome shell]$ for i in "${flower[@]}";do echo $i;done lily Chinese rose tulip [peter@ibi-genome shell]$ for i in ${flower[*]};do echo $i;done lily Chinese rose tulip [peter@ibi-genome shell]$ for i in ${flower[@]};do echo $i;done lily Chinese rose tulip
for循环我们在后面的控制结构中还会详细学习。不用引号时${flower[*]}和${flower[@]}中的第1个元素"Chinese rose"都扩展成了两个词。
5. 变量输出
Shell变量输出可以用echo或printf命令。echo命令比较简单,我们前面已经学习过。printf是格式化输出,语法与C语言的printf一致。如:
[peter@ibi-genome shell]$ a=10 [peter@ibi-genome shell]$ echo $a 10 [peter@ibi-genome shell]$ printf "%d\n" $a 10 [peter@ibi-genome shell]$ printf "%.2f\n" $a 10.00
6. 变量删除
如果一个变量不再使用,可以用unset命令删除。但如果该变量已经用readonly命令定义为只读变量,则不能用unset删除。
[peter@ibi-genome shell]$ echo $color red [peter@ibi-genome shell]$ unset color [peter@ibi-genome shell]$ echo $color
Shell变量使用比较灵活,尤其是变量内容删除和替换,在编程实践中善于利用可提高编程效率。但Shell的语法要求很严,与Perl宽松的语法形成鲜明对比。