0

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?

Dave
  • 727
  • 1
  • 9
  • 20
  • `arr_errors_found=()` should not be inside the loop, it should be before the loop. You're emptying the array each time through the loop. – Barmar Apr 06 '22 at 22:45
  • I removed the array from the loop, but now it only checks how many files are scanned instead of every entry grepped in every file. – Dave Apr 06 '22 at 23:18
  • Since you put `$found_error_entry` in quotes, it's just one word. You need to set `IFS` to newline and omit the quotes there. – Barmar Apr 06 '22 at 23:38
  • 1
    If you want the count, why not use `grep -c`? – Barmar Apr 06 '22 at 23:38
  • @Barmar, I tried using `arr_errors_found+=$found_error_entry` and setting `IFS=$'\n'` (even though I think `IFS=` uses new line by default), same problem. Also the point of the IFS while loop is not just to count number of entries found from the grep statement off each file, its also to gather each line that matches the grep. Besides I use the number of indexes in the array (`${#arr_errors_found[@]}`) to count so `grep -c` is not necessary. – Dave Apr 07 '22 at 12:29
  • You need parentheses: `IFS=$'\n' arr_errors_found+=($found_error_entry)`. The default IFS is newline, space, and tab. – Barmar Apr 07 '22 at 13:50
  • @Barmar, I figured it out, posted my own answer. – Dave Apr 07 '22 at 13:57

1 Answers1

0

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.

Dave
  • 727
  • 1
  • 9
  • 20