配列に mapfile でファイルの内容やコマンドの出力を読み込む

mapfile のオプション

オプション 説明
-d delim delim を各入力行の区切り文字として使用する
-n count 最大で count で指定した行数を配列にコピーする。count を指定しない場合はすべての行を配列にコピーする
-O origin origin で指定したインデックスを配列にコピーする開始位置にする。origin を指定しない場合は 0 が使用される
-s count 入力行の最初の count 行をスキップする
-t 各入力行の末尾から区切り文字を削除する
-u fd 入力行を標準入力の代わりに fd で指定したファイルディスクリプタから読み取る
-C callback-c オプションで指定した行数を読み込むときに実行される callback を指定する
-c quantum -C オプションで指定したコールバックを実行するのに読み込む行数を指定する

mapfile の使用例

オプションを指定せずに mapfile を使用した場合、配列の要素には区切り文字(デフォルトで改行)が含まれます。

code
cat << 'EOF' > data.txt
AAA BBB
CCC DDD
EOF

mapfile array < data.txt

declare -p array
stdout
declare -a array=([0]=$'AAA BBB\n' [1]=$'CCC DDD\n')
code
cat << 'EOF' > data.txt
AAA BBB
CCC DDD
EOF

mapfile < data.txt

# mapfile に配列名を指定しない場合は MAPFILE 変数に読み込まれる
declare -p MAPFILE
stdout
declare -a MAPFILE=([0]=$'AAA BBB\n' [1]=$'CCC DDD\n')

mapfile -t 区切り文字の削除

配列から区切り文字(改行)を取り除くには -t オプションを指定します。

code
cat << 'EOF' > data.txt
AAA BBB
CCC DDD
EOF

mapfile -t array < data.txt

declare -p array
stdout
declare -a array=([0]="AAA BBB" [1]="CCC DDD")

mapfile -u ファイルディスクリプタを指定する

入力を標準入力以外にする場合は -u オプションを使用します。以下は -u オプションに 5 を指定して 5 のファイルディスクリプタから読み込むようにしています。

code
cat << 'EOF' > data.txt
AAA BBB
CCC DDD
EOF

mapfile -t -u 5 array 5< data.txt

declare -p array
stdout
declare -a array=([0]="AAA BBB" [1]="CCC DDD")

mapfile コマンドの出力を読み込む

以下はコマンドの出力を mapfile で配列に読み込むサンプルです。

code
mapfile -t array < <(cat << 'EOF'
LINE1
LINE2
EOF
)

declare -p array
stdout
declare -a array=([0]="LINE1" [1]="LINE2")

mapfile -d 区切り文字を指定する

区切り文字をデフォルトの改行から変更したい場合は -d オプションで区切り文字を指定します。

code
printf '%s' "A,B,C,D" > data.txt

mapfile -t -d ',' array < data.txt

declare -p array
stdout
declare -a array=([0]="A" [1]="B" [2]="C" [3]="D")

mapfile -n 読み取る最大行数を指定する

読み取りを行う最大行数(リミット)を -n オプションで指定することができます。

code
cat << 'EOF' > data.txt
LINE-1
LINE-2
LINE-3
LINE-4
EOF

# 2行だけ読み込み
mapfile -t -n 2 array < data.txt

declare -p array
stdout
declare -a array=([0]="LINE-1" [1]="LINE-2")

mapfile -s 読み取りを指定行数スキップする

mapfile の -s オプションにスキップする行数を指定することで、読み取りを指定行数スキップすることができます。

code
cat << 'EOF' > data.txt
LINE-1
LINE-2
LINE-3
LINE-4
EOF

# 先頭から2行スキップして読み込み
mapfile -t -s 2 array < data.txt

declare -p array
stdout
declare -a array=([0]="LINE-3" [1]="LINE-4")

mapfile -O 配列にコピーする開始位置を指定する

mapfile の -O オプションで配列にコピーする開始位置を指定することができます。

code
cat << 'EOF' > data.txt
LINE-1
LINE-2
EOF

declare -a array=('ORIGIN-1' 'ORIGIN-2')

# 入力を配列のインデックス1以降に読み込み
mapfile -t -O 1 array < data.txt

declare -p array
stdout
declare -a array=([0]="ORIGIN-1" [1]="LINE-1" [2]="LINE-2")
code
cat << 'EOF' > data.txt
LINE-1
LINE-2
EOF

declare -a array=('ORIGIN-1' 'ORIGIN-2')

# 入力を配列のインデックス2以降に読み込み
mapfile -t -O 2 array < data.txt

declare -p array
stdout
declare -a array=([0]="ORIGIN-1" [1]="ORIGIN-2" [2]="LINE-1" [3]="LINE-2")

入力を読み込む時に処理を実行する

mapfile の -C オプションで入力を読み込むときに実行されるコールバックを指定することができます。-c オプションで指定した行数を読み込むたびに実行されます。

code
cat << 'EOF' > data.txt
LINE-1
LINE-2
LINE-3
LINE-4
EOF

declare -a array=()

# $1=配列のインデックス, $2=配列の要素
callback() {
  echo "index=${1} value=${2} array=${array[@]}"
}

# 入力を読み込むたびに -C に指定したコールバックを実行する
mapfile -t -C callback -c 1 array < data.txt

declare -p array
stdout
index=0 value=LINE-1 array=
index=1 value=LINE-2 array=LINE-1
index=2 value=LINE-3 array=LINE-1 LINE-2
index=3 value=LINE-4 array=LINE-1 LINE-2 LINE-3
declare -a array=([0]="LINE-1" [1]="LINE-2" [2]="LINE-3" [3]="LINE-4")
code
cat << 'EOF' > data.txt
LINE-1
LINE-2
LINE-3
LINE-4
EOF

declare -a array=()

# $1=配列のインデックス, $2=配列の要素
callback() {
  echo "index=${1} value=${2} array=${array[@]}"
}

# 入力を2行読み込むたびに -C に指定したコールバックを実行する
mapfile -t -C callback -c 2 array < data.txt

declare -p array
stdout
index=1 value=LINE-2 array=LINE-1
index=3 value=LINE-4 array=LINE-1 LINE-2 LINE-3
declare -a array=([0]="LINE-1" [1]="LINE-2" [2]="LINE-3" [3]="LINE-4")

注意点は -c オプションを指定しない場合は実行されないことです。

code
cat << 'EOF' > data.txt
LINE-1
LINE-2
EOF

callback() {
  echo "called"
}

# -c オプションを指定しない場合は実行されない
mapfile -t -C callback array < data.txt

declare -p array
stdout
declare -a array=([0]="LINE-1" [1]="LINE-2")