Home > Enterprise >  Iterate between two arrays within a single loop
Iterate between two arrays within a single loop

Time:05-02

I have these variables:

bridge_xa_name_list=( "$br_int0_srxa" "$br_int1_srxa" "$br_int2_srxa" "$br_int6_srxa" "$br_int7_srxa" "$br_wan3_srxa1" "$br_wan3_srxa2" )
bridge_xb_name_list=( "$br_int0_srxb" "$br_int1_srxb" "$br_int2_srxb" "$br_int6_srxb" "$br_int7_srxb" "$br_wan3_srxb1" "$br_wan3_srxb2" )

I am trying to use a single loop to iterate all the elements for each array.

At the moment I have a functioning loop but only by referencing the $bridge_xa_name_list

   for a in "${bridge_xa_name_list[@]}"; do
        shell_echo_textval_green "Network Bridge Name Detected" "$a"

        sleep 1
        shell_echo_text "Verifying $a network State"
        virsh_net_list=$(virsh net-list | grep active | grep $a)    

        if [[ ! $virsh_net_list == *"active" ]]
        then
            shell_echo "[Inactive]"
        else
            shell_echo "[Active]"
            shell_echo_green "$a.xml found. Undefining anyway."
            virsh net-undefine $a
        fi
            
        shell_echo_text "File $a.xml is at $srxa_fld_path"
        if [[ -f ${srxa_fld_path}${a}.xml ]]
        then
            shell_echo "[Yes]"
        else
            shell_echo "[Not Found]"
            shell_echo_text "Attempting to copy $a.xml template to ~/config/$srxa_nm"
            cp $xml_file_path $srxa_fld_path${a}.xml
            shell_echo ["Copied"]

            #Check if Copy was sucessfull
                if [[ -f $srxa_fld_path${a}.xml ]]
                then    
                    :
                else
                    shell_echo_red "[Failed]"
                    shell_echo_red "There was an error when trying to copy ${a}.xml"
                    shell_echo_error_banner "Script Aborted! 1 error(s)"
                    exit 1              
                fi
done

$a in my script is iterating all the elements from the 1st array. However, I would like to include the second array as part of the same loop.

CodePudding user response:

These are indexed arrays so you can iterate over the indexes:

for (( i = 0; i < ${#bridge_xa_name_list[@]}; i   )); do
  echo "${bridge_xa_name_list[i]}"
  echo "${bridge_xb_name_list[i]}"
done

CodePudding user response:

$a in my script is iterating all the elements from the 1st array. However, I would like to include the second array as part of the same loop.

I think you mean that you want to execute the loop body once for each element of bridge_xa_name_list and also once, separately, for each element of bridge_xb_name_list, without duplicating the body of the loop. Yes, there are at least two easy ways to do that:

  1. Absolutely easiest would be to just specify the additional elements in the loop header:

    for a in "${bridge_xa_name_list[@]}" "${bridge_xb_name_list[@]}"; do
      # loop body ...
    

    What you need to understand here is that the for loop syntax has nothing in particular to do with accessing an array. The in list of such a command designates zero or more individual values (shell "words") to iterate over, which in the case of your original code are produced by a parameter expansion involving array-valued parameter bridge_xa_name_list. But this is just a special case of the shell's general procedure of expanding each command (path expansion, parameter expansion, command expansion, etc.) before executing it. You can use that however you like.

    OR

  2. Make a function around the loop that executes it once for every function argument. Then call that function once for each array:

    my_loop() {
      for a in "$@"; do
        # loop body
      done
    }
    
    # ...
    
    my_loop "${bridge_xa_name_list[@]}"
    my_loop "${bridge_xb_name_list[@]}"
    

    Note that this still exhibits the same expand-then-execute behavior described in the previous item, which is why you have to pass the expansion of each array (to one word per element). There is no direct way to pass the whole array as a single argument.

    Note also that the shell supports a special shortcut for iterating over all the elements of $@. For that particular case, you can omit the in list altogether:

    my_loop() {
      for a; do
        # loop body
      done
    }
    

Of course, you can also combine the above, by providing the function and calling it once with the elements of both arrays:

my_loop "${bridge_xa_name_list[@]}" "${bridge_xb_name_list[@]}"
  • Related