Linux, Mac下Shell 数组 Array 的修理工
2015-01-22 03:29
190 查看
我的测试基本都是在Mac,及Unix环境下测试的,如无特别注明,默认就是Mac
不论你看到这篇随笔是被shell array的奇淫巧技,还是发现shell array就在一对{}里面就可以做那么多勾当,然而记不清楚了,当然有可能发现不管是用$*还是$@数组长度都是1,这可怎么办,还是小白,我就从我碰壁的过程中得到的碎屑整理一二,打通你的任督二脉
Shell是有很多种的
/bin/sh (已经被 /bin/bash 所取代)
/bin/bash (就是 Linux预设shell,bash 主要兼容sh,而且依据一些使用者需求而加强的shell 版本)
一般认为是1979年, Stephen Bourne发明的,他为UNIX写了第一个主要的shell程序,并命名为Bourne Shell,后来几乎所有的UNIX的shell都是源自它,后来一个新的加强版的逐渐成熟,成为Bourne Again Shell (Bash),在继承"老版"sh的基础上添加了很多功能,一般这个加强或者扩充是Brian Fox以及Chet Ramey完成的
/bin/csh (已经被 /bin/tcsh 所取代)
与Bourne Shell同时,University of California, Berkeley的Bill Joy提出了C Shell的思想,Joy认识到Bourne shell的不足(无法后台运行),决定用C语言中的保留字设计C Shell。
/bin/ksh (Kornshell 由 AT&T Bell lab. 开发出来的,兼容bash的)
与csh同时,贝尔实验室的David Korn也发明了Korn Shell 来修复C Shell中的不足,并且完全兼容Bourne Shell,而且ksh新版本还提供window功能。
/bin/tcsh (整和 C Shell ,提供更多的功能)
1975年, Carnegie Mellon University的Ken Greer受TENEX操作系统启发开始实现Tenex-style文件名补全功能,1981年整合C Shell 然后1983年 Mike Ellis有加入了命令补全功能,最终在1983年发布。
/bin/zsh (基于 ksh发展出来的,功能更强大的shell)
是1990年princeton University的一个学生Paul Falstad写的第一版
以Bash为标准来说明
A数组创建
无非就是2中几乎所有的编程语言都有的方法,一种单个赋值,一种是一起()赋值(1,2)。还有两种不正常的(3,4)
array[0]=one;array[1]=two;array[2]=three # 0-based
array=(one two three) #用空格分隔开来
array=([0]=one [1]=two [2]=three) #用空格分隔开来,0-based
array="one two three" #也是可以的,这样就把bash array的本质暴露出来了,就是个字符串
B复制数组
new_array=($old_array_name)
new_array=${old_array_name[@]}
new_array=${old_array_name[*]}
new_array=($@) #如果在函数中的话,只有B.1这种,因为$@无法写成${@[@]}
#记得这对括号,只要字符串是以空格分隔的,加一对括号,就变数组,Perl的匿名数组和哈希就用的这套思路
# 加不加括号数组长度一样,但是不加的话,数组的第一个值变成了真个数组的字符串,有用的track就是定义数组的时候array[0]空着,从array[1]开始
C数组下标系统
${array[index]} #绝大多数语言的index都是0-based,Shell也支持0-based
D数组和各元素长度
${#array[@]} #数组元素的个数
${#array[*]} #数组元素的个数
${#array
} #第n个元素的字符串长度
举个例子来验证一下我说的长度和下标,下面4种分贝对应A创建数组部分的4中形式,
然后看一下各种定义数组的长度时候一样,以及第1个和第2个元素是什么
结果如下,说明4重情况长度都是正常计算的
从结果就可以看出,字符串按数组方式引用的话,就被看作一个元素的数组(array_str),而加了括号之后,就被转换成数组(array_fstr),说明四种都可以的
然后在验证函数中的情况,虽大同,但也有小异
我们来写一个函数,验证$*和$@的不同,以及复制数组是否一致
和整个shell脚本一样,函数也可以用位置变量来引用,$1,$2,$3,$4, ... ...
结果分析就是,无论是$*还是$@在复制到新array中的时候都要加括号,不然第一个元素被整个数组字符串覆盖,我们由此想,把第一个元素的位置空出来不就行了吗?但是我还不知道怎么弄
E数组切片
用习惯了Perl的数组分片,Perl从Bash借鉴了很多东西来
${array:m} #切处第m个元素(included)开始的所有元素切片,为字符串,赋值都是字符串
${array:m:n} #切处第m个元素(included)开始n个元素的切片,为字符串,赋值都是字符串
new_slice=({array:m:n})
F元素字符(串)替换/删除
第一个
${array[n|@|*]/what/replacement} #把第n+1个元素/[b]所有元素匹配到what的[/b]把what字符(串)替换成replacement,并不会对原数组改变
new_array=${array[@]/what/replacement}
new_element=${array
/what/replacement}
简单说就是:会对你没个指定的元素执行what->replacement的替换,但是只会对每个元素中what第一次出现的位置进行替换,如果某个元素字符串含有多个what字符(串),则只替换第一个
全局的
${array[n|@|*]//what/replacement} # 把第n+1个元素/所有元素匹配到what的把what字符(串)替换成replacement,并不会对原数组改变
new_array=${array[@]//what/replacement}
简单说就是:会对你没个指定的元素执行what->replacement的替换,但是会对每个元素中每个出现what的位置都进行替换,即使某个元素字符串含有多个what字符(串),也都会被替换掉
replacement为空即为删除,不支持通配符匹配
Fig G.1
Fig G.2
H元素字符(串)删除
可以使用通配符*(元字符)
${array[n|@|*]#pattern} #删除每个元素中符合pattern的部分,匹配最短,如pattern为u*n,元素为ubunbunbuntu的话,则切的是ubun,留的是bunbuntu, Fig H.1
${array[n|@|*]##pattern} #删除每个元素中符合pattern的部分,匹配最长,如pattern为u*n,元素为ubunbunbuntu的话,则切的是ubunbunbun,留的是tu, Fig H.1
${array[n|@|*]%pattern} #删除每个元素中符合pattern的部分,匹配最短,如pattern为n*u,元素为ubunbunbuntu的话,则切的是ntu,留的是ubunbunbu, Fig H.2
${array[n|@|*]%%pattern} #删除每个元素中符合pattern的部分,匹配最长,如pattern为n*u,元素为ubunbunbuntu的话,则切的是nbunbuntu,留的是ubu, Fig H.2
千万注意:限制是必须匹配某一头,#时必须匹配开头,%是=时必须匹配末尾,就是你必须从某一头连续切,不能在中间切一段, Fig H.3
Fig H.1
Fig H.2
Fig H.3
既然字符串可以看作是单个元素的数组,那上面这一套都适合Bash中的字符串处理
Reference:
1. http://bbs.chinaunix.net.sixxs.org/thread-1779167-1-1.html
2. http://www.cnblogs.com.sixxs.org/chengmo/archive/2010/09/30/1839632.html
3. 鸟哥的Linux私房菜 基础版 (第三版)
4. http://en.wikipedia.org/wiki/Tcsh
不论你看到这篇随笔是被shell array的奇淫巧技,还是发现shell array就在一对{}里面就可以做那么多勾当,然而记不清楚了,当然有可能发现不管是用$*还是$@数组长度都是1,这可怎么办,还是小白,我就从我碰壁的过程中得到的碎屑整理一二,打通你的任督二脉
Shell是有很多种的
/bin/sh (已经被 /bin/bash 所取代)
/bin/bash (就是 Linux预设shell,bash 主要兼容sh,而且依据一些使用者需求而加强的shell 版本)
一般认为是1979年, Stephen Bourne发明的,他为UNIX写了第一个主要的shell程序,并命名为Bourne Shell,后来几乎所有的UNIX的shell都是源自它,后来一个新的加强版的逐渐成熟,成为Bourne Again Shell (Bash),在继承"老版"sh的基础上添加了很多功能,一般这个加强或者扩充是Brian Fox以及Chet Ramey完成的
/bin/csh (已经被 /bin/tcsh 所取代)
与Bourne Shell同时,University of California, Berkeley的Bill Joy提出了C Shell的思想,Joy认识到Bourne shell的不足(无法后台运行),决定用C语言中的保留字设计C Shell。
/bin/ksh (Kornshell 由 AT&T Bell lab. 开发出来的,兼容bash的)
与csh同时,贝尔实验室的David Korn也发明了Korn Shell 来修复C Shell中的不足,并且完全兼容Bourne Shell,而且ksh新版本还提供window功能。
/bin/tcsh (整和 C Shell ,提供更多的功能)
1975年, Carnegie Mellon University的Ken Greer受TENEX操作系统启发开始实现Tenex-style文件名补全功能,1981年整合C Shell 然后1983年 Mike Ellis有加入了命令补全功能,最终在1983年发布。
/bin/zsh (基于 ksh发展出来的,功能更强大的shell)
是1990年princeton University的一个学生Paul Falstad写的第一版
以Bash为标准来说明
A数组创建
无非就是2中几乎所有的编程语言都有的方法,一种单个赋值,一种是一起()赋值(1,2)。还有两种不正常的(3,4)
array[0]=one;array[1]=two;array[2]=three # 0-based
array=(one two three) #用空格分隔开来
array=([0]=one [1]=two [2]=three) #用空格分隔开来,0-based
array="one two three" #也是可以的,这样就把bash array的本质暴露出来了,就是个字符串
B复制数组
new_array=($old_array_name)
new_array=${old_array_name[@]}
new_array=${old_array_name[*]}
new_array=($@) #如果在函数中的话,只有B.1这种,因为$@无法写成${@[@]}
#记得这对括号,只要字符串是以空格分隔的,加一对括号,就变数组,Perl的匿名数组和哈希就用的这套思路
# 加不加括号数组长度一样,但是不加的话,数组的第一个值变成了真个数组的字符串,有用的track就是定义数组的时候array[0]空着,从array[1]开始
C数组下标系统
${array[index]} #绝大多数语言的index都是0-based,Shell也支持0-based
D数组和各元素长度
${#array[@]} #数组元素的个数
${#array[*]} #数组元素的个数
${#array
} #第n个元素的字符串长度
举个例子来验证一下我说的长度和下标,下面4种分贝对应A创建数组部分的4中形式,
array_str="ubuntu deepin elementory opensuse fedora centos" array_ot[0]=ubuntu;array_ot[1]=deepin;array_ot[2]=elementory;array_ot[3]=opensuse;array_ot[4]=fedora;array_ot[5]=centos array_ar=(ubuntu deepin elementary opensuse fedora centos) array_bl=([0]=ubuntu [1]=deepin [2]=elementory [3]=opensuse [4]=fedora [5]=centos) array_fstr=($array_str)
然后看一下各种定义数组的长度时候一样,以及第1个和第2个元素是什么
echo *********************Length********************* echo -e array_str@,${#array_str[@]},"\t${array_str[0]}>>>${array_str[1]}" echo -e array_fstr*,${#array_fstr[*]},"\t${array_fstr[0]}>>>${array_fstr[1]}" echo -e array_ot,${#array_ot[@]},"\t${array_ot[0]}>>>${array_ot[1]}" echo -e array_ar,${#array_ar[@]},"\t${array_ar[0]}>>>${array_ar[1]}" echo -e array_bl,${#array_bl[@]},"\t${array_bl[0]}>>>${array_bl[1]}"
结果如下,说明4重情况长度都是正常计算的
从结果就可以看出,字符串按数组方式引用的话,就被看作一个元素的数组(array_str),而加了括号之后,就被转换成数组(array_fstr),说明四种都可以的
然后在验证函数中的情况,虽大同,但也有小异
我们来写一个函数,验证$*和$@的不同,以及复制数组是否一致
和整个shell脚本一样,函数也可以用位置变量来引用,$1,$2,$3,$4, ... ...
function say(){ echo -e " ****************From say\033[00m" echo -e "Length \$@ ",${#@},"\t$1>>>$2" echo -e "Length \$* ",${#*},"\t$1>>>$2" args=($@) echo -e "\033[01;32m>>>>>>>>> args=(\$@)\033[00m" echo -e "Length \$args*",${#args[*]},"\t${args[0]}>>>${args[1]}>>>${args[2]}" echo -e "Length \$args@",${#args[@]},"\t${args[0]}>>>${args[1]}>>>${args[2]}" args=$@ echo -e "\033[01;32m>>>>>>>>> args=\$@\033[00m" echo -e "Length \$args*",${#args[*]},"\t${args[0]}>>>${args[1]}>>>${args[2]}" echo -e "Length \$args@",${#args[@]},"\t${args[0]}>>>${args[1]}>>>${args[2]}" args=($*) echo -e "\033[01;32m>>>>>>>>> args=(\$*)\033[00m" echo -e "Length \$args*",${#args[*]},"\t${args[0]}>>>${args[1]}>>>${args[2]}" echo -e "Length \$args@",${#args[@]},"\t${args[0]}>>>${args[1]}>>>${args[2]}" args=$* echo -e "\033[01;32m>>>>>>>>> args=\$*\033[00m" echo -e "Length \$args*",${#args[*]},"\t${args[0]}>>>${args[1]}>>>${args[2]}" echo -e "Length \$args@",${#args[@]},"\t${args[0]}>>>${args[1]}>>>${args[2]}" } echo -ne "\033[01;31m=================> \${array_ar[@]}" say ${array_ar[@]} echo -ne "\033[01;31m=================> $array_str" say $array_str
结果分析就是,无论是$*还是$@在复制到新array中的时候都要加括号,不然第一个元素被整个数组字符串覆盖,我们由此想,把第一个元素的位置空出来不就行了吗?但是我还不知道怎么弄
admin@iMac:~ => array_ar=("ubuntu" "deepin" "elementary" "opensuse" "fedora" "centos");n=${#array_ar[@]};for ss in `seq 0 $n`;do echo -e "$ss\t${array_ar[$ss]}\t"${#array_ar[$ss]}; done 0 ubuntu 6 1 deepin 6 2 elementary 10 3 opensuse 8 4 fedora 6 5 centos 6 6 0
E数组切片
用习惯了Perl的数组分片,Perl从Bash借鉴了很多东西来
${array:m} #切处第m个元素(included)开始的所有元素切片,为字符串,赋值都是字符串
${array:m:n} #切处第m个元素(included)开始n个元素的切片,为字符串,赋值都是字符串
new_slice=({array:m:n})
F元素字符(串)替换/删除
第一个
${array[n|@|*]/what/replacement} #把第n+1个元素/[b]所有元素匹配到what的[/b]把what字符(串)替换成replacement,并不会对原数组改变
new_array=${array[@]/what/replacement}
new_element=${array
/what/replacement}
简单说就是:会对你没个指定的元素执行what->replacement的替换,但是只会对每个元素中what第一次出现的位置进行替换,如果某个元素字符串含有多个what字符(串),则只替换第一个
全局的
${array[n|@|*]//what/replacement} # 把第n+1个元素/所有元素匹配到what的把what字符(串)替换成replacement,并不会对原数组改变
new_array=${array[@]//what/replacement}
简单说就是:会对你没个指定的元素执行what->replacement的替换,但是会对每个元素中每个出现what的位置都进行替换,即使某个元素字符串含有多个what字符(串),也都会被替换掉
replacement为空即为删除,不支持通配符匹配
Fig G.1
Fig G.2
H元素字符(串)删除
可以使用通配符*(元字符)
${array[n|@|*]#pattern} #删除每个元素中符合pattern的部分,匹配最短,如pattern为u*n,元素为ubunbunbuntu的话,则切的是ubun,留的是bunbuntu, Fig H.1
${array[n|@|*]##pattern} #删除每个元素中符合pattern的部分,匹配最长,如pattern为u*n,元素为ubunbunbuntu的话,则切的是ubunbunbun,留的是tu, Fig H.1
${array[n|@|*]%pattern} #删除每个元素中符合pattern的部分,匹配最短,如pattern为n*u,元素为ubunbunbuntu的话,则切的是ntu,留的是ubunbunbu, Fig H.2
${array[n|@|*]%%pattern} #删除每个元素中符合pattern的部分,匹配最长,如pattern为n*u,元素为ubunbunbuntu的话,则切的是nbunbuntu,留的是ubu, Fig H.2
千万注意:限制是必须匹配某一头,#时必须匹配开头,%是=时必须匹配末尾,就是你必须从某一头连续切,不能在中间切一段, Fig H.3
Fig H.1
Fig H.2
Fig H.3
既然字符串可以看作是单个元素的数组,那上面这一套都适合Bash中的字符串处理
Reference:
1. http://bbs.chinaunix.net.sixxs.org/thread-1779167-1-1.html
2. http://www.cnblogs.com.sixxs.org/chengmo/archive/2010/09/30/1839632.html
3. 鸟哥的Linux私房菜 基础版 (第三版)
4. http://en.wikipedia.org/wiki/Tcsh
相关文章推荐
- Linux Bash Shell学习(十六):数组
- Shell 数组元素个数${#array[@]} 数组的所有元素${array[*]} 字符串长度${#str}
- shell 数组(in_array)
- Linux下shell数组
- Linux下获取IP、MAC、掩码的shell脚本
- 演示了如何在Linux的Shell中使用数组.
- Linux和Mac中当前目录打开终端(shell)
- Linux 中 Shell 中的数组(将命令行参数作为数组的元素)
- Linux下Shell中数组的使用
- linux的简单shell脚本包括数组和条件判断
- @shell脚本中数组array常用技巧学习实践@
- Linux下获取IP、MAC、网关、掩码的shell脚本
- Shell 数组元素个数${#array[@]} 数组的所有元素${array[*]} 字符串长度${#str}
- shell脚本中数组array常用技巧学习实践
- 并行编程之跨平台使用SSE、AVX指令集心得——以单精度浮点数组求和为例(支持vc、gcc,兼容Windows、Linux、Mac)
- shell中的array数组
- linux边学边记--变量键盘读取、数组与声明:read 、array、declare、变量修改及设置方式
- [C] 跨平台使用Intrinsic函数范例1——使用SSE、AVX指令集 处理 单精度浮点数组求和(支持vc、gcc,兼容Windows、Linux、Mac)
- Linux下获取IP、MAC、网关、掩码的shell脚本
- Linux和Mac中当前目录打开终端(shell)