0

I have a pretty simple sh script where I make a system cat call, collect the results and parse some relevant information before storing the information in an array, which seems to work just fine. But as soon as I exit the for loop where I store the information, the array seems to clear itself. I'm wondering if I am accessing the array incorrectly outside of the for loop. Relevant portion of my script:

    #!/bin/sh

    declare -a QSPI_ARRAY=()

    cat /proc/mtd | while read mtd_instance
    do
        # split result into individiual words
        words=($mtd_instance)
        for word in "${words[@]}"
        do
            # check for uboot 
            if [[ $word == *"uboot"* ]]
            then
                mtd_num=${words[0]}
                index=${mtd_num//[!0-9]/}    # strip everything except the integers
                QSPI_ARRAY[$index]="uboot"
                echo "QSPI_ARRAY[] at index $index: ${QSPI_ARRAY[$index]}"

            elif [[ $word == *"fpga_a"* ]]
            then
                echo "found it: "$word""
                mtd_num=${words[0]}
                index=${mtd_num//[!0-9]/}    # strip everything except the integers
                QSPI_ARRAY[$index]="fpga_a"
                echo "QSPI_ARRAY[] at index $index: ${QSPI_ARRAY[$index]}"

            # other items are added to the array, all successfully

            fi
        done
        echo "length of array: ${#QSPI_ARRAY[@]}"
        echo "----------------------"
    done

My output is great until I exit the for loop. While within the for loop, the array size increments and I can check that the item has been added. After the for loop is complete I check the array like so:

    echo "RESULTING ARRAY:"
    echo "length of array: ${#QSPI_ARRAY[@]}"
    for qspi in "${QSPI_ARRAY}"
    do
        echo "qspi instance: $qspi"
    done

Here are my results, echod to my display:

    dev:    size   erasesize  name

    length of array: 0
    -------------
    mtd0: 00100000 00001000 "qspi-fsbl-uboot"

    QSPI_ARRAY[] at index 0: uboot

    length of array: 1
    -------------
    mtd1: 00500000 00001000 "qspi-fpga_a"

    QSPI_ARRAY[] at index 1: fpga_a

    length of array: 2
    -------------

    RESULTING ARRAY:
    length of array: 0
    qspi instance:

EDIT: After some debugging, it seems I have two different arrays here somehow. I initialized the array like so: QSPI_ARRAY=("a" "b" "c" "d" "e" "f" "g"), and after my for-loop for parsing the array it is still a, b, c, etc. How do I have two different arrays of the same name here?

chepner
  • 497,756
  • 71
  • 530
  • 681
Allen
  • 162
  • 2
  • 3
  • 15
  • 3
    Your shebang, if it is used at all, needs to be `#!/bin/bash`. `/bin/sh` does not support arrays. – chepner Sep 23 '16 at 01:01

2 Answers2

1

Is this potentially what you are seeing:

http://mywiki.wooledge.org/BashFAQ/024

georges
  • 175
  • 4
  • 17
1

This structure:

cat /proc/mtd | while read mtd_instance
do
...
done

Means that whatever comes between do and done cannot have any effects inside the shell environment that are still there after the done.

The fact that the while loop is on the right hand side of a pipe (|) means that it runs in a subshell. Once the loop exits, so does the subshell. And all of its variable settings.

If you want a while loop which makes changes that stick around, don't use a pipe. Input redirection doesn't create a subshell, and in this case, you can just read from the file directly:

while read mtd_instance
do
...
done </proc/mtd

If you had a more complicated command than a cat, you might need to use process substitution. Still using cat as an example, that looks like this:

while read mtd_instance
do
...
done < <(cat /proc/mtd)

In the specific case of your example code, I think you could simplify it somewhat, perhaps like this:

#!/usr/bin/env bash    
QSPI_ARRAY=()
while read -a words; do␣
  declare -i mtd_num=${words[0]//[!0-9]/}
  for word in "${words[@]}"; do
    for type in uboot fpga_a; do
      if [[ $word == *$type* ]]; then
        QSPI_ARRAY[mtd_num]=$type
        break 2
      fi
    done
  done
done  </proc/mtd
Mark Reed
  • 91,912
  • 16
  • 138
  • 175