bash的变量与数组

变量:存储单个元素的内存空间; 也相当于是数组的0号索引。
数组:存储多个元素的连续的内存空间;

一、变量

1、介绍:

任何程序都需要变量。 变量是用来存储数据的。程序=指令+数据。
按照其变量是否需要严格定义其类型来划分 :

  1. 强类型语言: 简单讲就是严格区分变量类型,使用之前必须要声明一个变量的类型。如C、Python。

  2. 弱类型语言: 不强制区分变量的类型,在使用之前不用明确声明一个变量的类型,有默认的类型,一般默认是字符型的,用到时直接使用,直接赋值。 如:bash。


定义变量类型的作用:

  1. 数据存储格式;

  2. 数据的有效存储范围,有效取值范围都不一样,如 C语言的 整型,长整型。

  3. 比较机制不同,运算类型也不同。如字符 2加上3,等于 23.  而数值就是5.

  4. 不同类型的数据不能运算, 只能转换以后再运算。


变量的命令要求: 变量名其实就是指向的内存空间地址

  1. 只能使用数字、字母和下划线组成;

  2. 不能以数字开头;

  3. 不能使用程序中的关键字;

  4. 要见名知义。命名机制遵循某种法则;不能够使用程序的保留字,例如if, else, then, while等等;


2、定义变量:

本地变量:只对当前shell进程有效,对其子shell及其它shell都无效。

  1. 定义变量:[set]Var_name="Value" 

  2. 引用变量:${Var_Name}

  3. 撤销变量:unset Var_Name


局部变量:仅对局部代码生效,只能在函数中使用。引用和撤销与上面相同

  1. 定义变量:local Var_Name="Value"


环境变量: 对当前shell及其子shell有效,所以在当前shell中所执行的脚本也可以使用这种变量,脚本的运行环境就是子shell。

  1. 定义变量:
    (1) export name=value
    (2) name=value ; export name    反过来也一样。
    (3) declare -x name=value
    (4) name=value ; declare -x name


位置变量:用以引用执行脚本或函数时的所调用的变量。

  1. $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


特殊变量:

  1. $0: 脚本名称自身。

  2. $?: 上一条命令的执行状态。状态返回值。状态用数字来表示: 0-255;0 成功;1-255: 失败。失败状态中: 1,2(命令参数错误),127(没有命令),255  是预留的。 我们可以手动定义其它的。

  3. $$   当前shell的PID

  4. $!    Shell最后运行的后台进程的PID

  5. $#   参数数量

  6. $*   所有参数

  7. $@   所有参数

  8. $-    使用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.....

  1. 查看环境变量:export, declare -x, printenv, env

  2. 撤销环境变量:unset name


只读变量:

  1. 定义变量:

    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"

字符串切片:

  1. ${var:offset:number}: 取字符串的子串, 变量:偏移数:取字符数。与数组索引一样,0表示第一个元素,只不过在变量里第一个元素就是表示第一个字符。

    echo ${hi:3:2}            值:lo   从第四个字符开始,取2个。


  2. 切片也支持负数,取字符串的最右侧的几个字符:${var:  -length}
    注意:以负数取值,冒号后必须有一个空白字符;如:${arr: -8} 显示后面的8个字符。

    echo ${hi: -2}            值:ld


  3. 也可以定义结束范围:echo ${arr:3:-9},3到-9之间的字符。3和-9只是用来标识位置的,而不是用来定义有哪些内容的,负数就是从右到左。而最终数据取值只能是从左到右。

    echo ${hi:3:-2}        值:lo Wor


基于模式取子串:

  1. ${var#*word}:其中word是指定的分隔符;
    功能:最短自左而右匹配,删除所有匹配到的字符。*是通配符。

    echo ${hi#?e}        值:llo World

    echo ${hi#*o}        值:World

    echo ${hi#*o W}    值:orld

    echo ${see#*/}        值:etc/systemd/system.conf


  2. ${var##*word}:其中word是指定的分隔符;

    功能:最长自左而右匹配,删除所有匹配到的字符。*是通配符。
    echo ${see##*/}        值:system.conf


  3. ${var%word*}:其中word是指定的分隔符;
    功能:最短自右而左匹配,删除所有匹配到的字符。

    echo ${see%/*}        值:/etc/systemd

    这个完成了取路径的目录名,而上面的##完成了取路径基名。


  4. ${var%%word*}:其中word是指定的分隔符;

    功能:最长自右而左匹配,删除所有匹配到的字符。

    echo ${see%%/*}        值:

    echo ${hi%%l*}        值:He

    url=https://www.google.com.hk

    echo ${url%%:*}        值:https



#号标识数据的首部。 %用来标识尾部。

hi变量保存有"Hello World"

查找替换:PATTERN中可以使用glob通配符;

  1. ${var/PATTERN/SUBSTI}:查找var所表示的字符串中,第一次被PATTERN所匹配到的字符串,并将其替换为SUBSTI所表示的字符串;
    echo ${hi/l/L}        值:HeLlo World

    echo ${hi/ll/LL}        值:HeLLo World

    echo ${hi/*o/L}        值:Lrld


  2. ${var//PATTERN/SUBSTI}:查找var所表示的字符串中,所有被PATTERN所匹配到的字符串,并将其全部替换为SUBSTI所表示的字符串;
    echo ${hi//l/L}        值:HeLLo WorLd


  3. ${var/#PATTERN/SUBSTI}:查找var所表示的字符串中,行首被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;比/多了限制,只能从左每一个字符开始匹配成功。

    echo ${hi/#l/L}        值:Hello World

    echo ${hi/#H/L}        值:Lello World

    echo ${hi/#*o/L}        值:Lrld


  4. ${var/%PATTERN/SUBSTI}:查找var所表示的字符串中,行尾被PATTERN所匹配到的字符串,将其替换为SUBSTI所表示的字符串;与上面意思一样,只不过是从右到左。


查找删除:(see为/etc/systemd/system.conf)

  1. ${var/PATTERN}:删除以PATTERN为模式第一次匹配到的var字符串。这里不用替换了,下接删除。

    与#不同的是,这个是定点删除,而#是范围删除。当然如果加上通配符也一样。

    echo ${see/\/systemd}        值:/etc/system.conf


  2. ${var//PATERN}  删除以PATTERN为模式所有匹配到的var字符串。


  3. ${var/#PATTERN}  以左边界匹配。


  4. ${var/%PATTERN}  以右边界匹配。



字符大小写转换:

  1. ${var^^}:把var中的所有小写字符转换为大写;

  2. ${var,,}:把var中的所有大写字符转换为小写;

    这个也可以用一个^或,来表示。 只转换一个字母。也可以用#或%来定义边界。


变量赋值:

  1. ${var:-VALUE}:如果var变量为空,或未设置,那么返回VALUE;否则,则返回var变量的值;

  2. ${var:=VALUE}:如果var变量为空,或未设置,那么返回VALUE,并将VALUE赋值给var变量;否则,则返回var变量的值;

  3. ${var:+VALUE}:如果var变量不空,则返回VALUE;

  4. ${var:?ERROR_INFO}:如果var为空,或未设置,那么返回ERROR_INFO为错误提示;否则,返回var值;

    而VALUE不单单只能用字符,也可以用变量引用来表示数据。


变量中字符的个数:

  1. ${#var}


二、数组:

在普通变量上面用到的功能,在数组上大部分也都可以使用。


数组名:整个数组只有一个名字;
数组索引:编号从0开始;0是第一个索引。
bash-4及之后的版本开始支持"关联数组",也就是索引不是以数字表示,而是以自定义的字符串来表示。

声明数组:
       declare  -a  NAME:声明索引数组;  这个不用显示的声明,赋值的同时就自动生成数组了。
       declare  -A  NAME:声明关联数组;  这个需要先在赋值之前声明。
       
赋值方式:

  1. 一次只赋值一个元素;
    ARRAY_NAME[INDEX]=value

    wKioL1a9nUmQkpgWAABLrI2YCRo805.png

    只给0和5赋值了,其它索引都没有值。


  2. 一次赋值全部元素;会把上面单独定义的覆盖

    wKioL1a9ndmQQR9iAABdZqVcKVI330.png

    可以看到,赋值索引是0,1,2 但是原来的5的值也没有了。


  3. 只赋值特定元素;这个也会覆盖数据。
    ARRAY_NAME=([0]="VAL1"  [3]="VAL4" ...)
    bash支持稀疏格式的数组;就是不按顺序来的索引。

    wKiom1a9nxijv7JoAABffLvhVj8465.png

  4. read  -a  ARRAY_NAME
    可以用read来获取输入为数组赋值。
    wKioL1a9m_bjJovaAAASeH__uBI956.png


也就只有第一种不会覆盖不同索引的数据。如:

  1. wKiom1a9n92wcisgAABVG5-i76U548.png




数组的长度(数组中元素的个数):

  1. ${#ARRAY_NAME[*]}

    echo ${#abc[*]}            5

    与变量一样,只不过这里元素个数,那里是字符个数。当然也可以查看某元素的字符的个数。

    echo ${#abc[1]}            3


  2. ${#ARRAY_NAME[@]}

    这个与*是一样的。

   
引用数组中的元素

  1. ${ARRAY_NAME[INDEX]}
    注意:引用时如果只给数组名,表示引用下标为0的元素;

  2. 引用数组中的所有元素:
    ${ARRAY_NAME[*]}
    ${ARRAY_NAME[@]}


数组元素切片:

  1. ${ARRAY_NAME[@]:offset:number}
    offset:偏移的元素个数;
    number:要取出的元素个数;省略number时,表示取偏移量之后的所有元素;
    ${arry[*]:3:2}
    加上*来输出所有数据,再由3和2来定位哪个位置
    如果不加*,数据只是一个字符块,会当做变量来操作。

    变量也可以这样偏移,而且个数部分还可以用负数。我们上面变量部分已经试过了。


字符大小写转换

  1. ${ARRAY_NAME[*]^^}:把数组中的所有元素转换为大写;

    wKiom1a9pOLR76uxAAAWhaeXaxk441.png

  2. ${ARRAY_NAME[0]^^}:把数组中的0索引元素转换为大写;
    wKioL1a9pXLAnROpAAAO1EIFR28506.png

  3. 也可以用一个^或,来表示只给首字母变化。
    wKiom1a9pU2yBlibAAAScW7VpU4273.png


追加元素:

  1. 因为索引是从0开始,正好与个数少1。所以只要计算出元素个数,给个数赋值即可。

  2. 只能是非稀疏格式的数组,因为稀疏格式是没有顺序的,可能有的索引位是8,但元素的个数却只有2个,这样追加追加,一会儿就把8给覆盖了。
    ARRAY_NAME[${#ARRAY_NAME[*]}]=
    红色部分是用来取出数组元素的个数。

  3. wKioL1a9qAixLiinAAA1ksrn6-c301.png


删除数组中的某元素:

  1. unset  ARRAY[INDEX]

    wKiom1a9qDeTx_s5AAAcJ8gmxeI153.png

  2. unset ARRAY            删除数组

    wKioL1a9qKbhvrgWAAAcJ8gmxeI446.png


关联数组:

  1. declare  -A  ARRAY_NAME
    ARRAY_NAME=([index_name1]="value1"  [index_name2]="value2" ...)
    index_name就是自定义的字符串,它来做为索引,或许称为键。赋值方式与索引数组也没有什么不同。

    wKiom1a9qb_gn64GAAAygtU-xu0892.png

    wKiom1a9qnzSPGdxAABm8aueZWU203.png



谢谢浏览。j_0022.gif