shell展开与shell数组
00 0 12 11
01 1 13 7
02 0 14 1
03 0 15 7
04 1 16 6
04 1 17 5
06 6 18 4
07 3 19 4
08 1 20 1
09 14 21 0
10 2 22 0
11 5 23 0
Total files = 80
1 |
|
这个脚本由一个函数(名为 usage),和一个分为四个区块的主体组成。
第一部分,我们检查是否有一个命令行参数, 且该参数为目录。如果不是目录,会显示脚本使用信息并退出。
第二部分初始化一个名为 hours 的数组。给每一个数组元素赋值一个0。虽然没有特殊需要在使用之前准备数组,但是我们的脚本需要确保没有元素是空值。注意这个循环构建方式很有趣。通过使用花括号展开({0..23}),我们能很容易为 for 命令产生一系列的数据(words)。
接下来的一部分收集数据,对目录中的每一个文件运行 stat 程序。我们使用 cut 命令从结果中抽取两位数字的小时字段。 在循环里面,我们需要把小时字段开头的零清除掉,因为 shell 将试图(最终会失败)把从 “00” 到 “09” 的数值解释为八进制。 下一步,我们以小时为数组索引,来增加其对应的数组元素的值。最后,我们增加一个计数器的值(count),记录目录中总共的文件数目。
脚本的最后一部分显示数组中的内容。我们首先输出两行标题,然后进入一个循环产生两栏输出。最后,输出总共的文件数目。
数组操作
输出整个数组的内容
下标 * 和 @ 可以被用来访问数组中的每一个元素。
1 | $ animals=("a dog" "a cat" "a fish") |
${animals[*]} 和 ${animals[@]}的行为是一致的直到它们被用引号引起来。
确定数组元素个数
1 | $ a[100]=foo |
把字符串赋值给数组元素100, bash 仅仅报告数组中有一个元素。
这不同于一些其它语言的行为,这种行为是数组中未使用的元素(元素0-99)会初始化为空值, 并把它们计入数组长度。
找到数组使用的下标
${!array[*]}
${!array[@]}
这里的 array 是一个数组变量的名字。和其它使用符号 * 和 @ 的展开一样,用引号引起来的 @ 格式是最有用的, 因为它能展开成分离的词。
1 | $ foo=([2]=a [4]=b [6]=c) |
在数组末尾添加元素
如果我们需要在数组末尾附加数据,那么知道数组中元素的个数是没用的,因为通过 * 和 @ 表示法返回的数值不能 告诉我们使用的最大数组索引。
shell 为我们提供了一种解决方案。通过使用+=赋值运算符, 我们能够自动地把值附加到数组末尾。这里,我们把三个值赋给数组 foo,然后附加另外三个。
1 | $ foo=(a b c) |
数组排序
1 |
|
1 | $ array-sort |
删除数组
1 | $ foo=(a b c d e f) |
也可以使用 unset 命令删除单个的数组元素:
1 | $ foo=(a b c d e f) |
注意数组元素必须 用引号引起来为的是防止 shell 执行路径名展开操作。
有趣地是,给一个数组赋空值不会清空数组内容:
1 | $ foo=(a b c d e f) |
任何没有下标的对数组变量的引用都指向数组元素0:
1 | $ foo=(a b c d e f) |
关联数组
现在最新的 bash 版本支持关联数组了。关联数组使用字符串而不是整数作为数组索引。 这种功能给出了一种有趣的新方法来管理数据。例如,我们可以创建一个叫做 “colors” 的数组,并用颜色名字作为索引。
1 | declare -A colors |
不同于整数索引的数组,关联数组必须用带有 -A 选项的 declare 命令创建。
1 | echo ${colors["blue"]} |