'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 |
