Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Iterate through multiple bash arrays in a for loop

I am facing the following issue and cannot think of a way to iterate multiple arrays from within one parent for loop.

For example, the current code is this:

main_array=("STRING1" "STRING2" "STRING3")
array1=(1 2 3)
array2=(4 5 6)
array3=(7 8 9)

I need the code that will print following output:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

STRING1
1
2
3
STRING2
4
5
6
STRING3
7
8
9

In essence, I need for loop that iterates through main_array (see above), then inside that loop another for loop that iterates array1. Once finished, parent for loop prints STRING2, then iterates throgh array2, and so on.

EDIT:

Here is my (truncated) attempt:

packages=("NETWORK" "FILE_SYSTEM")

NETWORK=(DBMS_LDAP UTL_INADDR UTL_TCP UTL_MAIL UTL_SMTP UTL_DBWS UTL_ORAMTS UTL_HTTP HTTPURITYPE)
FILE_SYSTEM=(DBMS_ADVISOR DBMS_LOB UTL_FILE)

for package in "${packages[@]}"; do

    echo "Ensure 'EXECUTE' is revoked from 'PUBLIC' on $package Packages"
    
    for i in ${NETWORK[@]}; do 
            /bin/echo -e "Current setting for $i:"
            RESULT=$(grep -Ei "^PUBLIC;.*$i;.*EXECUTE.*" file.txt)

            if [[ -z "$RESULT" ]]; then
                /bin/echo -e "Setting for $i is properly configured.\n"
            else
                /bin/echo -e "[!] This is not recommended setting! EXECUTE privilege should not be enabled for $i\n"
            fi
        done
        
    done

OUTPUT:

======================================================================
Ensure 'EXECUTE' is revoked from 'PUBLIC' on NETWORK Packages
======================================================================
[+] Current setting for DBMS_LDAP: 
PUBLIC;SYS;DBMS_LDAP;SYS;EXECUTE;NO;NO
[!] This is not recommended setting! EXECUTE privilege should not be enabled for DBMS_LDAP

[+] Current setting for UTL_INADDR: 
PUBLIC;SYS;UTL_INADDR;SYS;EXECUTE;NO;NO
[!] This is not recommended setting! EXECUTE privilege should not be enabled for UTL_INADDR

***TRUNCATED REPETITIVE - REST OF NETWORK ARRAY IS PRINTED HERE*** 
***CHILD FOR LOOP IS OVER, MAIN ARRAY STARTS***
======================================================================
Ensure 'EXECUTE' is revoked from 'PUBLIC' on FILE SYSTEM Packages
======================================================================
[+] Current setting for DBMS_LDAP: 
**##### Issue here, needs to iterate values from FILESYSTEM array** 
PUBLIC;SYS;DBMS_LDAP;SYS;EXECUTE;NO;NO
[!] This is not recommended setting! EXECUTE privilege should not be enabled for DBMS_LDAP

Thank you!

>Solution :

OP has provided two sets of input arrays which are going to require slightly different solutions …

Looking at the 1st set of arrays:

$ typeset -p main_array array1 array2 array3
declare -a main_array=([0]="STRING1" [1]="STRING2" [2]="STRING3")
declare -a array1=([0]="1" [1]="2" [2]="3")
declare -a array2=([0]="4" [1]="5" [2]="6")
declare -a array3=([0]="7" [1]="8" [2]="9")

Looks like we can just loop based on the numerical indexes of the main_array[] array while using a nameref to dynamically pick the appropriate array# array …

One idea:

for ((i=0; i<${#main_array[@]}; i++))
do
    echo "${main_array[i]}"
    declare -n curr_array="array$((i+1))"       # nameref

    for ((j=0; j<"${#curr_array[@]}"; j++))
    do
        echo "${curr_array[j]}"
    done
done

This generates:

STRING1
1
2
3
STRING2
4
5
6
STRING3
7
8
9

Looking at the 2nd set of arrays:

$ typeset -p packages NETWORK FILE_SYSTEM
declare -a packages=([0]="NETWORK" [1]="FILE_SYSTEM")
declare -a NETWORK=([0]="DBMS_LDAP" [1]="UTL_INADDR" [2]="UTL_TCP" [3]="UTL_MAIL" [4]="UTL_SMTP" [5]="UTL_DBWS" [6]="UTL_ORAMTS" [7]="UTL_HTTP" [8]="HTTPURITYPE")
declare -a FILE_SYSTEM=([0]="DBMS_ADVISOR" [1]="DBMS_LOB" [2]="UTL_FILE")

A slight variation will have us using the value of the packages[] array, as opposed to the index, to determine the nameref, eg:

for ((i=0; i<${#packages[@]}; i++))
do
    echo "${packages[i]}"
    declare -n curr_array="${packages[i]}"      # nameref

    for ((j=0; j<"${#curr_array[@]}"; j++))
    do
        echo "    ${curr_array[j]}"
    done
done

This generates:

NETWORK
    DBMS_LDAP
    UTL_INADDR
    UTL_TCP
    UTL_MAIL
    UTL_SMTP
    UTL_DBWS
    UTL_ORAMTS
    UTL_HTTP
    HTTPURITYPE
FILE_SYSTEM
    DBMS_ADVISOR
    DBMS_LOB
    UTL_FILE

NOTE:

Both solutions use the same inner loop to process the nameref array via index:

for ((j=0; j<"${#curr_array[@]}"; j++))
do
    echo "${curr_array[j]}"
done

We can also loop through the nameref array by referencing the array’s values:

for j in "${curr_array[@]}"
do
    echo "$j"
done
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading