1

I'm trying to read the information of a structured file into an associative array using Bash script. The file contains in each line the name of a person and its address, separated by a "|". For example:

person1|address of person1
person2|address of person2
...
personN|address of personN

I tried to do this using the script below. Within the WHILE loop, the information is being printed. However, in the FOR loop the information is not being printed. It seems that the information is not being stored in the associative array outside of the WHILE loop.

What am I doing wrong? Why this is not working? Is there more efficient ways to do that?

#!/bin/bash
declare -A address
cat adresses.txt | while read line
do
    name=`echo $line | cut -d '|' -f 1`
    add=`echo $line | cut -d '|' -f 2`
    address[$name]=$add
    echo "$name - ${address[$name]}"
done

for name in ${!address[*]}
do
    echo "$name - ${address[$name]}"
done
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Zaratruta
  • 2,097
  • 2
  • 20
  • 26
  • Possible duplicate of [bash4 read file into associative array](https://stackoverflow.com/questions/25251353/bash4-read-file-into-associative-array) – Léa Gris Sep 18 '19 at 14:26

3 Answers3

9

Wrong and useless usage of cut

#!/bin/bash
declare -A address
while IFS=\| read name add
do
    address[$name]=$add
done < adresses.txt

for name in ${!address[*]}
do
    echo "$name - ${address[$name]}"
done
Ipor Sircer
  • 3,069
  • 3
  • 10
  • 15
  • 3
    `cut` in the OP's code was just inefficient, not wrong. `cat`, however, was both useless and wrong. – chepner Nov 02 '16 at 20:17
  • I'm sorry. I've made a mistake in the script. But I've fixed the original post. The cut command is working properly. And I can access the information of the associative array within the WHILE loop. However, I'm not able to access it in the FOR loop. – Zaratruta Nov 02 '16 at 20:33
5
cat addresses.txt | while read line
do
    ...
done

Shell commands in a pipelines are executed in subshells. Variables set in subshells aren't visible the parent shell.

You can fix this by replacing the pipelines with a redirection.

while read line
do
    ...
done < addresses.txt
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • Yes! That was the problem! However, now I have another problem. If the person name has spaces, the FOR loop does not work properly. – Zaratruta Nov 02 '16 at 20:55
2

Extending the accepted answer to resolve the OP's comment:

#!/bin/bash
declare -A address
while IFS='|' read name add
do
    address[$name]=$add
    echo "$name - ${address[$name]}"
done < adresses.txt

for name in "${!address[@]}"
do
    echo "$name - ${address[$name]}"
done
na6cet
  • 41
  • 2