'bash how to append to an array inside a IFS while loop

I have the following script:

#!/bin/bash

pstdout="PASS"
fstdout="FAIL"
error_string_check="ERROR"

stdout_result(){
    result="$1"
    shift
    des="$1"
    shift
    reason="$1"
    shift
    arr_error_context=("$@")

    echo -e "[$result] $des"
    echo "       \`$reason"
    for i in "${arr_error_context[@]}"; do
        echo "         - $i"
    done


}

main(){
    for i in $(seq 1 3); do 
        for j in $(seq 1 10); do 
            echo "Entry $j, ERROR somethings broken." >> "testfile$i"
        done
        for k in $(seq 11 20); do 
            echo "Entry $k, INFO everythings good." >> "testfile$i"
        done
    done

    found_files="$(find ./ | grep testfile)"

    while IFS= read -r file_to_check; do 
        found_error_entry="$(cat $file_to_check | grep "$error_string_check")"
        arr_errors_found=()
        if [ -n "$found_error_entry" ]; then
            arr_errors_found+=("$found_error_entry")
        fi
        if [ ${#arr_errors_found[@]} -eq 0 ]; then
            stdout_result "$pstdout" "check for no \"$error_string_check\"in $file_to_check of all time."
        else
            stdout_result "$fstdout" "check for no \"$error_string_check\" in $file_to_check of all time." "error\(s\) were found:" "${arr_errors_found[@]}"
        fi
    done <<< "$found_files"


}


main
rm -f ./testfile1
rm -f ./testfile2
rm -f ./testfile3

However my output is this

[FAIL] check for no "ERROR" in ./testfile1 of all time.
       `1 error\(s\) were found:
         - Entry 1, ERROR somethings broken.
Entry 2, ERROR somethings broken.
Entry 3, ERROR somethings broken.
Entry 4, ERROR somethings broken.
Entry 5, ERROR somethings broken.
Entry 6, ERROR somethings broken.
Entry 7, ERROR somethings broken.
Entry 8, ERROR somethings broken.
Entry 9, ERROR somethings broken.
Entry 10, ERROR somethings broken.
[FAIL] check for no "ERROR" in ./testfile3 of all time.
       `1 error\(s\) were found:
         - Entry 1, ERROR somethings broken.
Entry 2, ERROR somethings broken.
Entry 3, ERROR somethings broken.
Entry 4, ERROR somethings broken.
Entry 5, ERROR somethings broken.
Entry 6, ERROR somethings broken.
Entry 7, ERROR somethings broken.
Entry 8, ERROR somethings broken.
Entry 9, ERROR somethings broken.
Entry 10, ERROR somethings broken.
[FAIL] check for no "ERROR" in ./testfile2 of all time.
       `1 error\(s\) were found:
         - Entry 1, ERROR somethings broken.
Entry 2, ERROR somethings broken.
Entry 3, ERROR somethings broken.
Entry 4, ERROR somethings broken.
Entry 5, ERROR somethings broken.
Entry 6, ERROR somethings broken.
Entry 7, ERROR somethings broken.
Entry 8, ERROR somethings broken.
Entry 9, ERROR somethings broken.
Entry 10, ERROR somethings broken.

As you can see the array does not keep its indexes. Shows only "1" error when there should be "10". I assume this is happening based on some subshell issue but I am not sure. I already tried to do what this post suggested, but it does not work.

Why does bash refuse to keep the indexes in the array? I need the number of errors printed, and every error printed with - appended to it. How can I accomplish this?



Solution 1:[1]

I figured it out. I first used a for loop to gather each file to check based on a grep, then built a IFS while loop to perform a grep on each file for "ERROR", then created nested IFS while loop to append found each grepped value to an array. I also adjusted my shifting, however this is unrelated to actual problem.

#!/bin/bash

pstdout="PASS"
fstdout="FAIL"
error_string_check="ERROR"

stdout_result(){
    #$1 = "PASS" or "FAIL"
    #$2 = description of check that was performed
    #$3 = reason for a failure (optional)
    #$4 = array of errors or failues to display

    result="$1"
    des="$2"
    reason="$3"
    shift 3
    arr_error_context=("$@")

    echo -e "${RED}[$result]${NC} $des"
    echo "       \`$reason"
    for i in "${arr_error_context[@]}"; do
        echo "         - $i"
    done
}

main(){
    for i in $(seq 1 3); do 
        for j in $(seq 1 10); do 
            echo "Entry $j, ERROR somethings broken." >> "testfile$i"
        done
        for k in $(seq 11 20); do 
            echo "Entry $k, INFO everythings good." >> "testfile$i"
        done
    done

    found_files="$(find ./ | grep testfile)"

    for file_to_check in "$(echo $found_files)"; do 
        while IFS=$'\n' read -r file_to_check; do 
            found_error_entry="$(cat $file_to_check | grep "$error_string_check")"
            arr_errors_found=()
            while IFS=$'\n' read -r each_entry; do 
                arr_errors_found+=("$each_entry")
            done <<< "$found_error_entry"
            if [ ${#arr_errors_found[@]} -eq 0 ]; then
                stdout_result "$pstdout" "check for no \"$error_string_check\"in $file_to_check of all time."
            else
                stdout_result "$fstdout" "check for no \"$error_string_check\" in $file_to_check of all time." "${#arr_errors_found[@]} error\(s\) were found:" "${arr_errors_found[@]}"
            fi
        done <<< "$found_files"
    done


}


main
rm -f ./testfile1
rm -f ./testfile2
rm -f ./testfile3

And the output after running:

[FAIL] check for no "ERROR" in ./testfile1 of all time.
       `10 error\(s\) were found:
         - Entry 1, ERROR somethings broken.
         - Entry 2, ERROR somethings broken.
         - Entry 3, ERROR somethings broken.
         - Entry 4, ERROR somethings broken.
         - Entry 5, ERROR somethings broken.
         - Entry 6, ERROR somethings broken.
         - Entry 7, ERROR somethings broken.
         - Entry 8, ERROR somethings broken.
         - Entry 9, ERROR somethings broken.
         - Entry 10, ERROR somethings broken.
[FAIL] check for no "ERROR" in ./testfile3 of all time.
       `10 error\(s\) were found:
         - Entry 1, ERROR somethings broken.
         - Entry 2, ERROR somethings broken.
         - Entry 3, ERROR somethings broken.
         - Entry 4, ERROR somethings broken.
         - Entry 5, ERROR somethings broken.
         - Entry 6, ERROR somethings broken.
         - Entry 7, ERROR somethings broken.
         - Entry 8, ERROR somethings broken.
         - Entry 9, ERROR somethings broken.
         - Entry 10, ERROR somethings broken.
[FAIL] check for no "ERROR" in ./testfile2 of all time.
       `10 error\(s\) were found:
         - Entry 1, ERROR somethings broken.
         - Entry 2, ERROR somethings broken.
         - Entry 3, ERROR somethings broken.
         - Entry 4, ERROR somethings broken.
         - Entry 5, ERROR somethings broken.
         - Entry 6, ERROR somethings broken.
         - Entry 7, ERROR somethings broken.
         - Entry 8, ERROR somethings broken.
         - Entry 9, ERROR somethings broken.
         - Entry 10, ERROR somethings broken.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dave