Search code examples
arraysbashdynamic-arrays

Array values reutilization in another array definition


I am trying to perform an array definition in bash using values of another array as the name of the new array and assign the values inside the array from another array which is dynamically populated.

Here is an example of the code so far:

adduser() {
  declare -i segment=$1
  segment_length=${#segment[@]}
  for (( a = 0; a < "${segment_length}"; a++ )); do
    data=($(cat $filename | grep -w ${segment[a]} | awk -F ";" '{print $1}' | tr '\n' ' ' | sed 's/^/ /g'))
    ${segment[a]}=($(echo "${data[*]}"))
  done
}

cat $filename | tail -n+2 | awk -F ";" '{print $2}' | awk '{ for (i=1; i<=NF; i++) print $i }' | sed 's/\r//g' | sort -u > segments.txt
IFS=$'\r\n' GLOBIGNORE='*' command eval  'segments=($(cat segments.txt))'
for (( i = 0; i < ${#segments[@]}; i++ )); do
adduser ${segments[i]}
done

The objective is to dynamically populate arrays (data in one column of csv) with values from another column and then massively work on them.

The csv has the following format:

Header1;Header2
Value1;1 2 3
Value2;2 4 5

Take for example the value 2 from column Header2. The objective is to dynamically create the array 2 with values Value1 and Value2:

2=( Value1 Value2 )

Testing the two answers provided:

I will continue here as comments are too short: Here is the result from the answer with a random file (same format as the example):

ivo@spain-nuc-03:~/Downloads/TestStackoverflow$ awk -F'[; ]' '/;[0-9] / { for (i=2; i<=NF; i++) printf "%s ", $1 > $i".txt" }' real.csv 
ivo@spain-nuc-03:~/Downloads/TestStackoverflow$ ll
total 68
drwxr-xr-x  2 ivo ivo  4096 Nov 27 17:16 ./
drwxr-xr-x 28 ivo ivo 32768 Nov 27 17:15 ../
-rw-rw-r--  1 ivo ivo    99 Nov 27 17:16 155.txt
-rw-rw-r--  1 ivo ivo   132 Nov 27 17:16 155?.txt
-rw-rw-r--  1 ivo ivo    99 Nov 27 17:16 2.txt
-rw-rw-r--  1 ivo ivo    66 Nov 27 17:16 2?.txt
-rw-rw-r--  1 ivo ivo   198 Nov 27 17:16 3.txt
-rw-rw-r--  1 ivo ivo    33 Nov 27 17:16 3?.txt
-rw-r--r--  1 ivo ivo  1369 Nov 27 17:14 real.csv

While with the answer above you get the following:

ivo@spain-nuc-03:~/Downloads/TestStackoverflow$ ./processing.sh real.csv

ivo@spain-nuc-03:~/Downloads/TestStackoverflow$ ll
total 112
drwxr-xr-x  2 ivo ivo  4096 Nov 27 17:25 ./
drwxr-xr-x 28 ivo ivo 32768 Nov 27 17:15 ../
-rw-rw-r--  1 ivo ivo   100 Nov 27 17:25 102.txt
-rw-rw-r--  1 ivo ivo   100 Nov 27 17:25 105.txt
-rw-rw-r--  1 ivo ivo    67 Nov 27 17:25 106.txt
-rw-rw-r--  1 ivo ivo    34 Nov 27 17:25 112.txt
-rw-rw-r--  1 ivo ivo   991 Nov 27 17:25 155.txt
-rw-rw-r--  1 ivo ivo   694 Nov 27 17:25 2.txt
-rw-rw-r--  1 ivo ivo   859 Nov 27 17:25 3.txt
-rw-rw-r--  1 ivo ivo    67 Nov 27 17:25 51.txt
-rw-rw-r--  1 ivo ivo    67 Nov 27 17:25 58.txt
-rw-rw-r--  1 ivo ivo    34 Nov 27 17:25 59.txt
-rw-rw-r--  1 ivo ivo    34 Nov 27 17:25 65.txt
-rw-rw-r--  1 ivo ivo    34 Nov 27 17:25 67.txt
-rw-rw-r--  1 ivo ivo    34 Nov 27 17:25 72.txt
-rw-rw-r--  1 ivo ivo    34 Nov 27 17:25 78.txt
-rw-rw-r--  1 ivo ivo    34 Nov 27 17:25 81.txt
-rw-rw-r--  1 ivo ivo    34 Nov 27 17:25 82.txt
-rwxrwxr-x  1 ivo ivo  1180 Nov 27 17:25 processing.sh*
-rw-r--r--  1 ivo ivo  1369 Nov 27 17:14 real.csv
ivo@spain-nuc-03:~/Downloads/TestStackoverflow$

Thanks to everyone for their participation!


Solution

  • All-bash using array -

    declare -a set=()                          # set is an array
    while IFS=';' read -r key lst              # read each line into these 2 splitting on semicolons
    do [[ $key =~ Header* ]] && continue       # ignore the header
       read -a val <<< "$lst"                  # split the list of values to the right of the semicolon into an array
       for e in "${val[@]}"                    # for each of those
       do  case "${set[e]:-}" in               
           *$key*) : already here, no-op   ;;  # ignore if already present
               '') set[e]="$key"           ;;  # set initial if empty
                *) set[e]="${set[e]} $key" ;;  # add delimited if new
           esac
       done
    done < csv                                 # reads directly from the CSV file
    

    At this point the sets should be loaded as space-delimited strings into each element of set[], indexed by the values on the line in the second column of the csv. To print them out for verification -

    for n in "${!set[@]}"
    do echo "$n: ${set[n]}"
    done
    

    Executed on the test csv content provided:

    1: Value1
    2: Value1 Value2
    3: Value1
    4: Value2
    5: Value2
    

    so set[4] is Value2, and set[2] is Value1 Value2. You can pull them from there to do whatever is needed.

    No need for cat/tail/awk/grep/tr/sed/sort chains.

    Does it need something more?