bash内置命令mapfile:读取文件内容到数组

bash提供了两个内置命令:readarray和mapfile,它们是同义词。它们的做用是从标准输入读取一行行的数据,而后每一行都赋值给一个数组的各元素。显然,在shell编程中更经常使用的是从文件、从管道读取,不过也能够从文件描述符中读取数据。html

须要先说明的是,shell并不像其它专门的编程语言对数组、列表提供了大量的操做工具,反而直接操做文本文件更为常见(sed、awk等),因此mapfile用的并很少。shell

1.语法

mapfile [OPTIONS] ARRAY
readarray [OPTIONS] ARRAY

其中options:
-O INDEX   :指定从哪一个索引号开始存储数据,默认存储数据的起始索引号为0
-n count   :最多只拷贝多少行到数组中,若是count=0,则拷贝全部行
-s count   :忽略前count行不读取
-c NUM     :每读取NUM行就调用一次"-C callback"选项指定的callback程序
-C callback:每读取"-c NUM"选项指定的NUM行就执行一次callback回调程序
-d string  :指定读取数据时的行分隔符,默认是换行符
-t         :移除尾随行分隔符,默认是换行符
-u fd      :指定从文件描述符fd而非标准输入中读取数据
  • 若是不指定ARRAY参数,则默认使用数组MAPFILE
  • 若是不指定"-O"选项,则在存储数据以前先清空数组(若是该数组已存在)
  • 给定了"-C callback"却没有给定"-c NUM"时,则默认为每5000行调用一次回调程序
  • 回调程序是在读取给定行数以后,赋值到数组元素以前执行的。因此流程为:"读NUM行-->callback-->赋值"
  • 每次调用回调函数时,都将调用callback以前的最后一行数据及其对应的索引号做为回调程序的参数。例如-c 3 -C callback,则会将索引号2和第3行内容,索引号5和第6行内容做为callback程序的参数
  • "-t"去除行尾分隔符,通常来讲都是换行符。用其余语言编程过的人都知道行尾换行符有多烦心,但对于shell编程来讲,却是无所谓

2.几个示例和注意事项

先建立一个示例用的文件alpha.log,每行一个小写字母,共26行:编程

$ echo {a..z} | tr " " "\n" >alpha.log
$ cat alpha.log
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z

读取该文件并将每一行存储到数组myarr中(若是不指定,则存储到默认的MAPFILE数组中)。数组

$ mapfile myarr <alpha.log
$ echo ${myarr[@]}
a b c d e f g h i j k l m n o p q r s t u v w x y z
$ echo ${myarr[2]}
c

既然是读取标准输入,常见的就有如下几种读取形式:bash

$ mapfile myarr <alpha.log            # 1.输入重定向
$ mapfile myarr < <(cat alpha.log)    # 2.进程替换
$ cat alpha.log | mapfile myarr       # 3.管道传递

第一、2种写法没什么问题,但第3种写法是有问题的。编程语言

$ cat alpha.log | mapfile myarr1
$ echo ${#myarr1[@]}
0

从结果中能够看到,myarr1根本就不存在。为何?我在shell中while循环的陷阱中给出过解释。这里简单说明一下,对于管道组合的多个命令,它们都会放进同一个进程组中,会进入子shell执行相关操做。当执行完毕后,进程组结束,子shell退出。而子shell中设置的环境是不会粘滞到父shell中的(即不会影响父shell),因此myarr1数组是子shell中的数组,回到父shell就消失了。函数

解决方法是在子shell中操做数组:工具

$ cat alpha.log | { mapfile myarr1;echo ${myarr1[@]}; }

mapfile能够指定每读取多少行就执行一次的回调函数,而且会将执行回调函数时读取的最后一行和对应的索引号传递给回调函数做为它额外的参数。code

一个简单的示例,每读取3行就执行一次echo,注意看下面传递给给echo的参数值。htm

$ mapfile -c 3 -C "echo" myarr <alpha.log
2 c

5 f

8 i

11 l

14 o

17 r

20 u

23 x

这里的echo就是回调函数。输出结果中每执行一次就有一空行,这是由于文件中数据是分行的,而echo又自带换行功能。因此,可使用"-t"选项,在每次读取一行后就去掉该行的换行符。

$ mapfile -t -c 3 -C "echo" myarr <alpha.log
2 c
5 f
8 i
11 l
14 o
17 r
20 u
23 x

能够写一个脚本,或者定义一个函数做为回调程序,实现更复杂的功能,但必定要注意,mapfile传递给callback的两个参数老是最后两个参数。例如:

$ myecho(){ echo $@; };mapfile -t -c 3 -C "myecho haha" myarr <alpha.log
haha 2 c
haha 5 f
haha 8 i
haha 11 l
haha 14 o
haha 17 r
haha 20 u
haha 23 x

还能够将多个操做组合起来做为一个回调程序:

$ mapfile -t -c 3 -C "echo haha;echo" myarr<alpha.log
haha
2 c
haha
5 f
haha
8 i
haha
11 l
haha
14 o
haha
17 r
haha
20 u
haha
23 x
相关文章
相关标签/搜索