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

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

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

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

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

第1、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可以指定每读取多少行就执行一次的回调函数,并且会将执行回调函数时读取的最后一行和对应的索引号传递给回调函数作为它额外的参数。

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

$ 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

bash内置命令mapfile:读取文件内容到数组的更多相关文章

  1. Bash内置命令exec和重定向

    Bash内置命令exec可以替换当前程序而不需要启动一个新的进程,可以改变标准输入和输出而不需要启动一个新的子进程.如果文件用exec打开,read命令就会把文件指针每次指向下一行直到文件的末尾,如果 ...

  2. bash内置命令的特殊性,后台任务的"本质"

    本文解释bash内置命令的特殊性.前台.后台任务的"本质",以及前.后台任务和bash进程.终端的关系.网上没类似的资料,所以都是自己的感悟和总结,如有错误,120分的期待盼请指正 ...

  3. Linux bash内置命令集

    man cd  -->查询不到,所以会提示bash的内置命令 . alias bg bind break builtin caller cd command compgen complete c ...

  4. Bash内置命令

    Bash有很多内置命令,因为这些命令是内置的,因此bash不需要在磁盘上为它们定位,执行速度更快. 1)列出所有内置命令列表$enable 2)关闭内置命令test$enable -n test 3) ...

  5. 哪一个 bash 内置命令能够进行数学运算?

    bash shell 的内置命令 let 可以进行整型数的数学运算. #! /bin/bash--let c=a+b--

  6. 哪一个 bash 内置命令能够进行数学运算?

    bash shell 的内置命令 let 可以进行整型数的数学运算. #! /bin/bash - - let c=a+b - -

  7. PHP 内置函数fgets读取文件

    php fgets()函数从文件指针中读取一行 语法: fgets(file,length) 参数 描述 file  必需.规定尧要读取的文件 length 可选 .规定尧都区的字节数.默认是102字 ...

  8. Linux内置命令

    主要Shell内置命令 Shell有很多内置在其源代码中的命令.这些命令是内置的,所以Shell不必到磁盘上搜索它们,执行速度因此加快.不同的Shell内置命令有所不同. A.2.1 bash内置命令 ...

  9. Shell内置命令

    主要Shell内置命令 Shell有很多内置在其源代码中的命令.这些命令是内置的,所以Shell不必到磁盘上搜索它们,执行速度因此加快.不同的Shell内置命令有所不同. A.2.1  bash内置命 ...

随机推荐

  1. HTML常用的特殊符号&前端使用的标点符号

    不想在项目中使用图片, 还得切,如关闭按钮“×”.男女符号“♂♀”.对勾“√”等,找到了一篇全面的博客,转自https://www.haorooms.com/post/html_tsfh,感谢. 如下 ...

  2. oracle 恢复table删除数据 恢复package(使用闪回)

    好久没写东西了,今天写一篇凑个数吧,来公司一年多了,感觉自己到了一个小瓶颈期了. 以前每天很多新东西,都是忙着学,感觉没时间写博客总结一下,大部分都是写笔记,现在又是没东西可以写,每天干着95%都是重 ...

  3. eclipse中设置python的版本

    (mac系统)由于系统的python是内置的,无法直接查找到安装文件,则可在eclipse偏好设置-PyDev - Interpreters-Python Interpreter其右边选择Quick ...

  4. flask-cookie & session

    Cookie @app.route('/') def hello_world(): name=request.cookies.get('Name')  # 获取cookie resp = Respon ...

  5. 急速安装lnmp 编译版本-wiki-shell脚本实现一键部署

    shell脚本lnmp.sh 环境:centos 6.5 .64位 #!/bin/bash yum install -y nano vim wget wget http://www.atomicorp ...

  6. Shader_ShaderForge_NGUI_序列帧/

    序列帧 Shader篇 Shader Forge序列帧算法! 附上Shader代码部分: // Shader created with Shader Forge v1.26 // Shader For ...

  7. 2018年3月24日上海MVP线下技术交流活动简报

    2018年3月24日下午,几位上海MVP自发组织了一次线下的技术交流会,主要由MVP胡浩牵头,我(陈晴阳).刘鑫.朱兴亮和胡浩各自做了一次主题演讲,具体主题是: 陈晴阳:<这还是我认识的Visu ...

  8. 深入理解JVM(二)——内存模型、可见性、指令重排序

    上一篇我们介绍了JVM的基本运行流程以及内存结构,对JVM有了初步的认识,这篇文章我们将根据JVM的内存模型探索java当中变量的可见性以及不同的java指令在并发时可能发生的指令重排序的情况. 内存 ...

  9. 网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

    1.前言 标题虽然是为了解释有了 IP 地址,为什么还要用 MAC 地址,但是本文的重点在于理解为什么要有 IP 这样的东西.本文对读者的定位是知道 MAC 地址是什么,IP 地址是什么. (本文同步 ...

  10. wordpress使用阿里云邮件推送服务实现发送邮件

    之前用腾迅云时,配置了wordpress是可以使用邮件服务的,然而到了阿里云,却无法使用了,有人说是因为阿里云关了25端口,但腾迅好像也关了. 百度看看有没有其他方法,最终让我找到个方法,可惜不是很完 ...