2

I searched the site very thoroughly but was not able to turn up a fitting answer - most probably I wasn't asking the correct questions.

I have a text-file with up to a several thousand lines of coordinates formatted as in the following example:

[1]
-75.4532 75.8273 
-115.00 64.5 
-90.00 74.3333 
-100.00 72.4167 
-110.00 69.00 
-120.8 56.284 
[2]
-70.00 73.75 
-100.00 69.3333 
-110.00 65.1533 
-90.00 71.5833 
-80.00 73.00 
[3]
-100.00 67.5 
-67.7133 72.6611 
-80.00 71.5 
-90.00 70.00 
-110.00 63.8667 
-115.8 60.836 

What I'm trying to achieve is to split the file into an array at the numbers in brackets. So that I can use the number in brackets as the arrays index and the following lines as the corresponding value.

The next step would be looping through the array feeding each element to another program. If there is a more elegant approach I'm willing to listen.

All the best!

2
  • Are you looking for a 2 dimensional array? Bash does not support that. Alternatively we could create one string for each index with lines separated by \n. DO you really want to store several thousand lines in memory at the same time? Commented Nov 7, 2013 at 15:47
  • I thought about where to store it and on average we are talking about 200 lines. The maximum is around 4000 lines and is a rare occurrence. Commented Nov 7, 2013 at 21:58

2 Answers 2

2

You can use sed to massage the file into a bash array definition:

declare -a "$(sed 's/\[/" &/g; s/\]/&="/g' file | sed '1s/^"/arr=(/; $s/$/")/')"
echo "${arr[2]}"
echo
echo ${arr[2]}
-70.00 73.75 
-100.00 69.3333 
-110.00 65.1533 
-90.00 71.5833 
-80.00 73.00 

-70.00 73.75 -100.00 69.3333 -110.00 65.1533 -90.00 71.5833 -80.00 73.00

Printing with and without quotes to demonstrate the difference

Sign up to request clarification or add additional context in comments.

2 Comments

Great idea though I think a single gawk would have been simpler using RS='\\[[0-9]+\\]'
glenn hackman, thank you for that sed example. I see where I did my mistake.
2

Use a combination of read -d (to set the record delimiter) and IFS (to set the field separator):

# read content from file
content="$(<input_filename)"

# append record separator to avoid dropping the last record
content="$content["

# read into array
arr=()
while IFS=']' read -d '[' sub value; do
    arr[$sub]=$value
done <<<"$content"

The resulting array will have an empty first element since it's zero-based. This can make it trickier to loop over it. You can remove the first element explicitly to make the loop easier:

unset arr[0]

Now you can loop over the elements:

for value in "${arr[@]}"; do
    program < "$value"
done

or if you need the 1-based index as well:

for ((i=1; i<=${#arr[@]}; i++)); do
    program "$i" "$value"
done

Hope that helps!

1 Comment

Very well explained answer. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.