bash的变量与数组
变量:存储单个元素的内存空间; 也相当于是数组的0号索引。
数组:存储多个元素的连续的内存空间;
一、变量
1、介绍:
任何程序都需要变量。 变量是用来存储数据的。程序=指令+数据。
按照其变量是否需要严格定义其类型来划分 :
- 强类型语言: 简单讲就是严格区分变量类型,使用之前必须要声明一个变量的类型。如C、Python。
- 弱类型语言: 不强制区分变量的类型,在使用之前不用明确声明一个变量的类型,有默认的类型,一般默认是字符型的,用到时直接使用,直接赋值。 如:bash。
定义变量类型的作用:
- 数据存储格式;
- 数据的有效存储范围,有效取值范围都不一样,如 C语言的 整型,长整型。
- 比较机制不同,运算类型也不同。如字符 2加上3,等于 23. 而数值就是5.
- 不同类型的数据不能运算, 只能转换以后再运算。
变量的命令要求: 变量名其实就是指向的内存空间地址
- 只能使用数字、字母和下划线组成;
- 不能以数字开头;
- 不能使用程序中的关键字;
- 要见名知义。命名机制遵循某种法则;不能够使用程序的保留字,例如if, else, then, while等等;
2、定义变量:
本地变量:只对当前shell进程有效,对其子shell及其它shell都无效。
- 定义变量:[set]Var_name="Value"
- 引用变量:${Var_Name}
- 撤销变量:unset Var_Name
局部变量:仅对局部代码生效,只能在函数中使用。引用和撤销与上面相同
- 定义变量:local Var_Name="Value"
环境变量: 对当前shell及其子shell有效,所以在当前shell中所执行的脚本也可以使用这种变量,脚本的运行环境就是子shell。
-
定义变量:
(1) export name=value
(2) name=value ; export name 反过来也一样。
(3) declare -x name=value
(4) name=value ; declare -x name
位置变量:用以引用执行脚本或函数时的所调用的变量。
- $1,$2......$n, 对应的就是第1、2、n个参数。数字两位的时候,要用{}括起来。
#!/bin/bash
#
echo "$1 $2 $3"
star@sst-pp:/tmp$ bash test.sh user group shell
user group shell
特殊变量:
- $0: 脚本名称自身。
- $?: 上一条命令的执行状态。状态返回值。状态用数字来表示: 0-255;0 成功;1-255: 失败。失败状态中: 1,2(命令参数错误),127(没有命令),255 是预留的。 我们可以手动定义其它的。
- $$ 当前shell的PID
- $! Shell最后运行的后台进程的PID
- $# 参数数量
- $* 所有参数
- $@ 所有参数
- $- 使用Set命令设定的Flag一览
下面摘自:http://blog.chinaunix.net/uid-26527046-id-3336483.html
$* :
位置参数从参数 1 开始。如果在双引号中进行扩展,则扩展就是一个词,由 IFS 特殊变量的第一个字符
将参数分开,如果 IFS 为空,则没有间隔空格。IFS 的默认值是空白、制表符和换行符。如果没有设置 IFS,
则使用空白作为分隔符(仅对默认 IFS 而言)。
$@ :
位置参数从参数 1 开始。如果在双引号中进行扩展,则每个参数都会成为一个词,因此 “$@” 与
“$1” “$2” 等效。如果参数有可能包含嵌入空白,那么您将需要使用这种形式。
bash内嵌的环境变量(通常为全大写字符):用于定义bash的工作环境
如:PATH, HISTFILE, HISTSIZE, HISTFILESIZE, HISTCONTROL, SHELL, HOME, UID, PWD, OLDPWD.....
- 查看环境变量:export, declare -x, printenv, env
- 撤销环境变量:unset name
只读变量:
-
declare -r name
readonly name
只读变量无法重新赋值,并且不支持撤销;存活时间为当前shell进程的生命周期,随shell进程终止而终止;
3、字符串变量修改:
只是输出,不是修改变量的值。通常用于赋值的时候。
变量是由bash提供的,所以一些操作也都支持glob风格的通配符。
下面在普通变量上面用到的功能,在数组上大部分也都可以使用。
以前写的,不怎么样,但是稍微详细点:
http://fanqie.blog.51cto.com/9382669/1649669
下面的例子中用到的变量:
hi变量保存有"Hello World"
see变量保存有"/etc/systemd/system.conf"
字符串切片:
-
${var:offset:number}: 取字符串的子串, 变量:偏移数:取字符数。与数组索引一样,0表示第一个元素,只不过在变量里第一个元素就是表示第一个字符。
echo ${hi:3:2} 值:lo 从第四个字符开始,取2个。
-
切片也支持负数,取字符串的最右侧的几个字符:${var: -length}
注意:以负数取值,冒号后必须有一个空白字符;如:${arr: -8} 显示后面的8个字符。
echo ${hi: -2} 值:ld
-
也可以定义结束范围:echo ${arr:3:-9},3到-9之间的字符。3和-9只是用来标识位置的,而不是用来定义有哪些内容的,负数就是从右到左。而最终数据取值只能是从左到右。
echo ${hi:3:-2} 值:lo Wor
基于模式取子串:
-
${var#*word}:其中word是指定的分隔符;
功能:最短自左而右匹配,删除所有匹配到的字符。*是通配符。
echo ${hi#?e} 值:llo World
echo ${hi#*o} 值:World
echo ${hi#*o W} 值:orld
echo ${see#*/} 值:etc/systemd/system.conf
-
${var##*word}:其中word是指定的分隔符;
功能:最长自左而右匹配,删除所有匹配到的字符。*是通配符。
echo ${see##*/} 值:system.conf
-
${var%word*}:其中word是指定的分隔符;
功能:最短自右而左匹配,删除所有匹配到的字符。
echo ${see%/*} 值:/etc/systemd
这个完成了取路径的目录名,而上面的##完成了取路径基名。
-
${var%%word*}:其中word是指定的分隔符;
功能:最长自右而左匹配,删除所有匹配到的字符。
echo ${see%%/*} 值:
echo ${hi%%l*} 值:He
url=https://www.google.com.hk
echo ${url%%:*} 值:https
#号标识数据的首部。 %用来标识尾部。
查找替换:PATTERN中可以使用glob通配符;
-
${var/PATTERN/SUBSTI}:查找var所表示的字符串中,第一次被PATTERN所匹配到的字符串,并将其替换为SUBSTI所表示的字符串;
echo ${hi/l/L} 值:HeLlo World
echo ${hi/ll/LL} 值:HeLLo World
echo ${hi/*o/L} 值:Lrld
-
${var//PATTERN/SUBSTI}:查找var所表示的字符串中,所有被PATTERN所匹配到的字符串,并将其全部替换为SUBSTI所表示的字符串;
echo ${hi//l/L} 值:HeLLo WorLd
-
${var/#PATTERN/SUBSTI}:查找var所表示的字符串中,行首被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;比/多了限制,只能从左每一个字符开始匹配成功。
echo ${hi/#l/L} 值:Hello World
echo ${hi/#H/L} 值:Lello World
echo ${hi/#*o/L} 值:Lrld
- ${var/%PATTERN/SUBSTI}:查找var所表示的字符串中,行尾被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;与上面意思一样,只不过是从右到左。
查找删除:(see为/etc/systemd/system.conf)
-
${var/PATTERN}:删除以PATTERN为模式第一次匹配到的var字符串。这里不用替换了,下接删除。
与#不同的是,这个是定点删除,而#是范围删除。当然如果加上通配符也一样。
echo ${see/\/systemd} 值:/etc/system.conf
- ${var//PATERN} 删除以PATTERN为模式所有匹配到的var字符串。
- ${var/#PATTERN} 以左边界匹配。
- ${var/%PATTERN} 以右边界匹配。
字符大小写转换:
- ${var^^}:把var中的所有小写字符转换为大写;
-
${var,,}:把var中的所有大写字符转换为小写;
这个也可以用一个^或,来表示。 只转换一个字母。也可以用#或%来定义边界。
变量赋值:
- ${var:-VALUE}:如果var变量为空,或未设置,那么返回VALUE;否则,则返回var变量的值;
- ${var:=VALUE}:如果var变量为空,或未设置,那么返回VALUE,并将VALUE赋值给var变量;否则,则返回var变量的值;
- ${var:+VALUE}:如果var变量不空,则返回VALUE;
-
${var:?ERROR_INFO}:如果var为空,或未设置,那么返回ERROR_INFO为错误提示;否则,返回var值;
而VALUE不单单只能用字符,也可以用变量引用来表示数据。
变量中字符的个数:
- ${#var}
二、数组:
在普通变量上面用到的功能,在数组上大部分也都可以使用。
数组名:整个数组只有一个名字;
数组索引:编号从0开始;0是第一个索引。
bash-4及之后的版本开始支持"关联数组",也就是索引不是以数字表示,而是以自定义的字符串来表示。
声明数组:
declare -a NAME:声明索引数组; 这个不用显示的声明,赋值的同时就自动生成数组了。
declare -A NAME:声明关联数组; 这个需要先在赋值之前声明。
赋值方式:
-
一次只赋值一个元素;
ARRAY_NAME[INDEX]=value
只给0和5赋值了,其它索引都没有值。 - 一次赋值全部元素;会把上面单独定义的覆盖 可以看到,赋值索引是0,1,2 但是原来的5的值也没有了。
-
只赋值特定元素;这个也会覆盖数据。
ARRAY_NAME=([0]="VAL1" [3]="VAL4" ...)
bash支持稀疏格式的数组;就是不按顺序来的索引。
-
read -a ARRAY_NAME
可以用read来获取输入为数组赋值。
也就只有第一种不会覆盖不同索引的数据。如:
数组的长度(数组中元素的个数):
-
${#ARRAY_NAME[*]}
echo ${#abc[*]} 5
与变量一样,只不过这里元素个数,那里是字符个数。当然也可以查看某元素的字符的个数。
echo ${#abc[1]} 3
-
${#ARRAY_NAME[@]}
这个与*是一样的。
引用数组中的元素:
-
${ARRAY_NAME[INDEX]}
注意:引用时如果只给数组名,表示引用下标为0的元素;
-
引用数组中的所有元素:
${ARRAY_NAME[*]}
${ARRAY_NAME[@]}
数组元素切片:
-
${ARRAY_NAME[@]:offset:number}
offset:偏移的元素个数;
number:要取出的元素个数;省略number时,表示取偏移量之后的所有元素;
${arry[*]:3:2}
加上*来输出所有数据,再由3和2来定位哪个位置
如果不加*,数据只是一个字符块,会当做变量来操作。
变量也可以这样偏移,而且个数部分还可以用负数。我们上面变量部分已经试过了。
字符大小写转换
- ${ARRAY_NAME[*]^^}:把数组中的所有元素转换为大写;
- ${ARRAY_NAME[0]^^}:把数组中的0索引元素转换为大写;
- 也可以用一个^或,来表示只给首字母变化。
追加元素:
- 因为索引是从0开始,正好与个数少1。所以只要计算出元素个数,给个数赋值即可。
-
只能是非稀疏格式的数组,因为稀疏格式是没有顺序的,可能有的索引位是8,但元素的个数却只有2个,这样追加追加,一会儿就把8给覆盖了。
ARRAY_NAME[${#ARRAY_NAME[*]}]=
红色部分是用来取出数组元素的个数。
删除数组中的某元素:
- unset ARRAY[INDEX]
- unset ARRAY 删除数组
关联数组:
-
declare -A ARRAY_NAME
ARRAY_NAME=([index_name1]="value1" [index_name2]="value2" ...)
index_name就是自定义的字符串,它来做为索引,或许称为键。赋值方式与索引数组也没有什么不同。