Home > Mobile >  Iterate through multiple bash arrays in a for loop
Iterate through multiple bash arrays in a for loop

Time:12-07

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:

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!

CodePudding user response:

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

A couple alternative methods for looping through the nameref array:

for j in "${!curr_array[@]}"                    # loop through indexes
do
       echo "${curr_array[j]}"
done 

##########

for j in "${curr_array[@]}"                     # loop through values
do
    echo "$j"
done

CodePudding user response:

Here's a truncated version of your truncated attempt, with old school nameref:

#!/bin/bash

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 "=== $package ==="

    array_ref="$package[@]"

    for i in "${!array_ref}"
    do
        echo "$i"
    done
done
=== 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

CodePudding user response:

Yes, you have the wrong data structure:

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

I see no reason to split things out.

  • Related