Shell数组介绍
2010-07-13 06:16:47 阿炯

bash中还可以使用数组变量,其赋值有两种:
(1) name = (value1 ... valuen) 此时下标从0开始

(2) name[index] = value

数组下标的范围没有任何限制,同时也不必使用连续的分量.
--------------------------------------------------
$ A=(a b c def)
=================================================
$ echo ${A[@]} //取全部元素
a b c def
=================================================
$ echo ${A[0]} //取第一个元素
a
=================================================
//取得数组元素的个数
$ echo ${#A[@]}
4
$ echo ${#A# }
4
$ echo ${#A[3]} //取得元素3的长度
$
==================================================
$ A[3]=yaoshuyin //将第三个元素重新赋值
$ echo ${A[@]}
a b c yaoshuyin
==================================================
//清除变量
$ unset A
$ echo ${A[@]}
$
==================================================
//清空变量,即将值变为空
$ A=
$ echo ${A[@]}
==================================================
A=B
B=C
unset $A 事实上所取消的变量是 B 而不是 A

从尾部开始提取:
array=( [0]=one [1]=two [2]=three [3]=four )
${array[@]:1} # two three four,除掉第一个元素后所有元素,那么${array[@]:0}表示所有元素
${array[@]:0:2} # one two
${array[@]:1:2} # two three

===================while循环===================
#建立数组
arrSource=("arrJobs.php" "arrSubHangye.php" "arrFirst.php" )
arrDest=("buildhr" \
"buildtrain/htdocs" \
"bankhr" \
"healthr" \
"elehr" \
)

#取数组无元素个数
lenArrSource=${#arrSource# }
lenArrDest=${#arrDest# }

#循环列出数组元素
i=0
while [ $i -lt $lenArrSource ]
do
echo ${arrSource[$i]}
let i++
done

--------------------------------
i=0
while [ $i -lt $lenArrDest ]
do

echo ${arrDest[$i]}
let i++
done

===================for循环===================
#源文件
arrSource=("/home/800hr/htdocs/login_jump.php")
#目标网站
arrDest=(ithr elehr buildhr bankhr healthr ctvhr chenhr mechr clothr cneduhr 56hr tourhr foodhr greenhr cnlawhr waimaohr)

for outer in ${arrSource
# } #${arrSource
# } 是数组中的所有元素
do
for inner in ${arrDest# }
do
echo "ln -s $outer /home/${inner}/campus/"
done
done

数组是一个包含多个值的变量。任何变量都可以在数组中使用。数组的尺寸没有最大限制,也不要求成员变量连续索引或者赋值。数组是基于0的:第一个元素的下标以0开始。

间接的声明使用以下的语法来声明一个变量:
ARRAY[INDEXNR]=value

INDEXNR 需要使用一个值为正数的数学表达式。

一个数组的外部声明使用内建命令 declare 来完成:
declare -a ARRAYNAME

一个带有索引值的声明也是可以接受的,但是索引值将被忽略。对数组的指定属性可以通过使用内建命令 declare 和 readonly。属性对数组中的所有变量起作用,你不能使用混合数组。

数组变量也可以使用这种格式的复合赋值来建立:
ARRAY=(value1 value2 ... valueN)

每个值将以这种形式 [indexnumber=]string 排列。索引号是可选的。如果提供,索引号就赋给它;otherwise the index of the element assigned is the number of the last index that was assigned, plus one. 这样的格式 declare 也可以接受。如果不提供索引值,那索引自动从零开始。

在数组中加入缺少或者额外的成员使用以下语法:
ARRAYNAME[indexnumber]=value

记住 read 内建命令提供 -a 选项,来允许对一个数组的成员变量进行读取和赋值。

------------------------
对数组的变量引用
为了指明在一个数组中的项目的内容,为了指向一个数组中的一个项目的内容,使用{}。这样是必须的,正如你可以从下面的例子看出,来绕过扩展操作符的shell解释。如果索引的数字是 @ 或者 *,一个数组的所有的成员都将被引用。
[hto in ~] ARRAY=(one two three)
[hto in ~] echo ${ARRAY[*]}
one two three
[hto in ~] echo $ARRAY[*]
one[*]
[hto in ~] echo ${ARRAY[2]}
three
[hto in ~] ARRAY[3]=four
[hto in ~] echo ${ARRAY[*]}
one two three four

不提供索引号码来指向某个数组的一个数字变量的内容和指向第一个元素的内容是一样的。

删除数组变量
unset 内建命令用来删除数组或者数组成员:
[hto in ~] unset ARRAY[1]
[hto in ~] echo ${ARRAY[*]}
one three four
[hto in ~] unset ARRAY
[hto in ~] echo ${ARRAY[*]}

--------------
数组的例子
很难找到数组使用的实际例子。你能在你的系统里找到相当多的并没有做多少事情的脚本,You will find plenty of scripts that don't really do anything on your system but that do use arrays to calculate mathematical series, for instance. And that would be one of the more interesting examples...most scripts just show what you can do with an array in an oversimplified and theoretical way.

The reason for this dullness is that arrays are rather complex structures. You will find that most practical examples for which arrays could be used are already implemented on your system using arrays, however on a lower level, in the C programming language in which most UNIX commands are written. A good example is the Bash history built-in command. Those readers who are interested might check the built-ins directory in the Bash source tree and take a look at fc.def, which is processed when compiling the built-ins.

shell - 文件名转化大小写
不用这么麻烦了,这是个比较经典的shell问题,正是shell发挥作用的时候
先提供两个方法:
1、
for uppercase in `ls`
do
for lowercase in `ls $uppercase|tr [A-Z] [a-z]`
do
mv $uppercase $lowercase 2>/dev/null
done
done

2、
typeset -u Lcase
for Ucase in `ls`
do
Lcase=$Ucase
mv $Ucase $Lcase
done

-------------------
大家完善并补充:
for file in `ls`
do
mv $file `echo $file|tr "[A-Z]" "[a-z]"`
done

--------------
用awk也行
#!/bin/sh
for I in `ls` ;
do
C=$(echo $I|awk '{print toupper($I)}')
mv $I $C
done

----------
for i in *
do
a=`echo $i |tr '[a-z]' '[A-Z]'`
cp $i $a
echo $a
rm -i $a
done

----------------------------
关于bash中数组的使用
一、基础
Bash只是提供了一维数组,但没有上限的限制。
1)声明
# declare -a name
这样就声明了一个name数组。

2)赋值
给数组的赋值可以参考普通变量的定义,如:
# name[0]=BeiJing
# name[1]=GuangZhou
# name[2]=ShenZhen
另外,还可以对整个数组赋值:
# name=([0]=BeiJing [1]=GuangZhou [2]=ShenZhen)

# name=(BeiJing GuangZhou ShenZhen)
数组元素之间以环境变量IFS的第一个字符来分割。即空格。若要跨过分隔符,可以这样做:
# name=("This is BeiJing" GuangZhou ShenZhen)

3)引用
引用数组,需要使用如下的架构,不要缺少了{}号:
引用
${name[subscript]}
例如:
# echo ${name[0]}
BeiJing
另外,还有两个特殊的符号,分别是*和@号,代指所有数组元素:
# echo ${name[ * ]}  //*两边没有空格,这里如此表示是因为exblog会识别错误
BeiJing GuangZhou ShenZhen
# echo ${name[@]}
BeiJing GuangZhou ShenZhen
显示整个数组元素数量,则用:
# echo ${#name[@]}
3

4)删除注销
就当普通的变量,使用unset即可:
# unset name

# unset name[0]

这里多在多讲解一些关于替换方面的应用,参考自互联网。

5)子串替换
[root@localhost shell]# array=( [0]=one [1]=two [2]=three [3]=four )
第一个匹配到的,会被删除
[root@localhost shell]# echo ${array[@] /o/m}
mne twm three fmur
所有匹配到的,都会被删除
[root@localhost shell]# echo ${array[@] //o/m}
mne twm three fmur
没有指定替换子串,则删除匹配到的子符
[root@localhost shell]# echo ${array[@] //o/}
ne tw three fur
替换字符串前端子串
[root@localhost shell]# echo ${array[@] /#o/k}
kne two three four
替换字符串后端子串
[root@localhost shell]# echo ${array[@] /%o/k}
one twk three four

二、升级
明白了数组的定义和使用,就可以在bash里面方便的使用了。假设,有如下的目录:
# ls -l
total 0
-rw-r--r--  1 root  wheel  0 Dec 28 11:39 001
-rw-r--r--  1 root  wheel  0 Dec 28 11:39 002
-rw-r--r--  1 root  wheel  0 Dec 28 17:49 003
-rw-r--r--  1 root  wheel  0 Dec 28 17:49 004
我现在要把这个目录下所有文件的文件名放到一个name数组中,方便在脚本里面使用。

# declare -a filename
# filename=(`ls -l|grep 00|awk '{print $9}'|sed -e :a -e '$!N;s/\\n/ /;ta'`)
# set|grep filename
filename=([0]="001" [1]="002" [2]="003" [3]="004")
# echo ${filename[@]}
001 002 003 004

上述的语句,其实就是使用了grep、awk、sed等把一列的字符转换为用()号包括,并用空格分开的字符串,这样就可以给filename数组赋值了。基于同样的原理,如果我们希望把一个文件里面一列的字符串都赋值到一个数组里面的话,可以这样:
# cat test
test-001
test-002
test-003
test-004
# filename=(`cat test|sed -e :a -e '$!N;s/\\n/ /;ta'`)
# set|grep filename
filename=([0]="test-001" [1]="test-002" [2]="test-003" [3]="test-004")

该文章最后由 阿炯 于 2022-06-06 09:01:38 更新,目前是第 2 版。