Douwe van der Leest
Douwe van der Leest

Reputation: 95

Reading an array from inputfile in bash

I am trying to clean up some code I wrote to run a few programs on files in an array in bash (version 4.2.46). In the scripts I am cleaning, I use an array with file names as keys and their relative paths as values (I know there are no extensions in the code below, these are assumed and/or added by the programs individually). This array can become quite big and therefore I want to separate it from the rest of my code, to improve readability of what the programs do.

The script I am currently using to read the inputfile is the following:

#!/bin/bash

mapfile -t FILE <$1

declare -A fileArray

while read line; do
    key=$(cut -d'=' -f1 <<< $line)
    value=$(cut -d'=' -f2 <<< $line)
    fileArray[$key]=$value
    echo "Key $key : Value ${fileArray[$key]}"
done <$1

echo "all keys : ${!fileArray[@]}"

This takes an input file, reads the lines, cuts it on the delimiter '=', passes the resulting strings on to MyArray as key and value and finaly echo's the keys and values of myArray to check whether the array actually functions as expected. Which it does. The input file contains the following text (in grey):

foo_bar1=foo1/foo_bar1
foo_bar2=foo2/foo_bar2
foo_bar3=foo3/foo_bar3

However, the inputfile is not an array and I can't find a package that is able to read an array from an input file without using the lines as value instead of the first part of the line as a key and the second part as the value belonging to that key. I would like the input file to look like the text below (in grey), if this means I don't have to explicitly parse the file line by line.

#!/bin/bash
declare -A fileArray=(
[foo_bar1]='foo1/foo_bar1'
[foo_bar2]='foo2/foo_bar2'
[foo_bar3]='foo3/foo_bar3'
)

Can you please help me clean up the miniscript for parsing an array or point me towards a package that does this for me?

Thanks in advance.

EDIT: I found that source can read the array (and any other variable) from the input file, without explicitely parsing it. This results in the following script, run as myScript.sh input.sh:

#!/bin/bash
source $1
declare -p fileArray

Which, in hindsight, was what I was looking for.

Upvotes: 4

Views: 107

Answers (2)

Inian
Inian

Reputation: 85865

If I understand your requirement right of not splitting the line to keys and values and directly use them, you could use a custom delimiter with IFS by setting it to = and read two values to set it

#!/usr/bin/env bash

declare -A fileArray

# Setting IFS value as '=' to delimit read on this character
while IFS== read -r key value; do
    fileArray["$key"]="$value"
done < file

declare -p fileArray

which produces an output as below which I hope is what you intended to do.

declare -A fileArray=([foo_bar2]="foo2/foo_bar2" [foo_bar3]="foo3/foo_bar3" [foo_bar1]="foo1/foo_bar1" )

Upvotes: 2

tshiono
tshiono

Reputation: 22062

How about:

#!/bin/bash

. <(
awk -F'=' '
BEGIN { print "declare -A ARRAY=(" }
{ print "[" $1 "]=\"" $2 "\"" }
END { print ")" }' inputfile )

echo "all keys : ${!ARRAY[@]}"

which yields:

all keys : foo_bar2 foo_bar3 foo_bar1

How it works:

The AWK script generates the lines

declare -A ARRAY=(
[foo_bar1]="foo1/foo_bar1"
[foo_bar2]="foo2/foo_bar2"
[foo_bar3]="foo3/foo_bar3"
)

and the part . <( ... ) performs process substitution to assign the array as you expect.

Upvotes: 2

Related Questions