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
相關文章
相關標籤/搜索