Search code examples
bashshellpipeassociative-arraywhiptail

Bash - Can't copy associative array if piping block output to command


With the following code I can't clone the associative array in Bash if piping to a command. I'm using Whiptail to display a progress bar:

#!/bin/bash 

declare -Ar ARR1=(
[a]='asdf'
[b]='qwerty'
[c]='yuio'
)

declare -A ARR2=()

clone() {
    {
        for key in "${!ARR1[@]}"; do
            ARR2[$key]="${ARR1[$i]}"

            echo "10"  # Hardcoded percentage for Whiptail
        done
    } | whiptail --gauge "Cloning" 6 60 0
}

clone

for key in "${!ARR2[@]}"; do
  echo "$key"
  echo "${ARR2[$i]}"
done

Removing the Whiptail pipe it works:

#!/bin/bash 

declare -Ar ARR1=(
[a]='asdf'
[b]='qwerty'
[c]='yuio'
)

declare -A ARR2=()

clone() {
    {
        for key in "${!ARR1[@]}"; do
            ARR2[$key]="${ARR1[$i]}"

            echo "10"  # Hardcoded percentage for Whiptail
        done
    }
}

clone

for key in "${!ARR2[@]}"; do
  echo "$key"
  echo "${ARR2[$i]}"
done

Is there a way to make this work with the Whiptail pipe?


Solution

  • Would you please try the following:

    #!/bin/bash
    
    declare -Ar ARR1=(
        [a]='asdf'
        [b]='qwerty'
        [c]='yuio'
    )
    
    declare -A ARR2=()
    
    clone() {
        {
            n=${#ARR1[*]}                   # number of items
            for key in "${!ARR1[@]}"; do
                ARR2[$key]="${ARR1[$key]}"
                (( i++ ))                   # increment a counter
                echo $(( 100 * i / n ))     # percentage
                sleep 1                     # wait for 1 sec
            done
        } > >(whiptail --gauge "Cloning" 6 60 0)
    }
    
    clone
    
    for key in "${!ARR2[@]}"; do
        echo "$key"
        echo "${ARR2[$key]}"
    done
    

    The key is the } > >(whiptail ... expression which keeps the enclosed block in the foreground process without using a pipeline.
    Please note that I have modified the code to display percentage to make it look like that.