2

When I declare an array in bash $ ARRAY=('ele1' ele2') I can append an element to it with $ ARRAY+=('ele3').

echo ${ARRAY[@]}
ele1 ele2 ele3

However, inside a script in a while loop I don't get it to work:

FOUNDFILES=$(ls -lA)
LINE_CNT=1
ARRAY=()

echo -e "$FOUNDFILES" | while read line
        do
                ARRAY+=("test")
                LINE_CNT=$((LINE_CNT+1))
        done

echo "${ARRAY[@]}"
echo $LINE_CNT

LINE_CNT variable delivers the amount of files that were found, but my array stays empty. What am I doing wrong?

9
  • 1
    You are printing echo "${FILE_ARRAY[@]}" instead of echo "${ARRAY[@]}", maybe that lead you to believe that ARRAY is empty. Commented Dec 11, 2019 at 15:52
  • 5
    Right hand side of a pipe runs in a subshell. Use while ... done < <(echo -e "$FOUNDFILES") isntead. Commented Dec 11, 2019 at 15:52
  • 1
    Also, capturing a list of files in a plain variable and echo -e are both unsafe ways to handle the file list. See my answer here for a safe way to do it. Commented Dec 11, 2019 at 15:57
  • @Socowi That was a copy,paste mistake, edited it. Have confusing file names in my real example. Commented Dec 11, 2019 at 16:12
  • @choroba This somehow creates an endless loop in my case, but I think this is the right track. while ... \ndo \ndoSomething \ndone < <(echo -e "$FOUNDFILES") Commented Dec 11, 2019 at 16:18

1 Answer 1

5

A few things:

  1. Don't assume that find outputs exactly one file name per line; that breaks in the presence of filenames containing newlines.

  2. Don't assume that newlines output by find are the only whitespace in the output.

  3. Don't use find at all when a glob will do.


shopt -s globstar
foundfiles=(./**/"$1")

declare -a array
line_cnt=1
for f in "${foundfiles[@]}"; do
    array+=(test)
    line_count=$((line_count + 1))
done

If your call to find is more complex than a glob can handle, and your version of find can output null-delimited file names, use

# -d for readarray was introduced in bash 4.4; earlier versions
# require something more complex; see Gordan Davidson's answer at
# https://stackoverflow.com/a/1120952/1126841
readarray -t -d $'\0' < <(find . ... -name "$1" -print0)

If your find does not support outputting null-delimited file names, rethink writing this in bash. (You might consider using zsh, which has a vastly richer set of glob features that can eliminate many cases where you would otherwise need find.)

Sign up to request clarification or add additional context in comments.

6 Comments

How to use this? ARRAY=(./**/"$1") didnt create an array
Furthermore there are no newlines in file names in my case.
Ok now I managed it to work. This is indeed very helpful. However this rather advises not to use find, not answering my question of what I was doing wrong namely not considering the creation of a subshell. FOUNDFILES=$(find . -name "$1") was just a placeholder, because I have this while loop in many scripts and I wondered why I could increment the counter but not modify the array.
Don't forget shopt -s globstar; - c.f. bash's manual
I find the assertion that one variable updates but the other does not dubious.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.