Reputation: 1262
I have an array of functions which I call inside a loop in bash. Whenever one of these functions returns an error, I keep track of it storing that function's name inside an error array to show to the user. This is the current working script.
#!/bin/bash
funA()
{
ls -e &> /dev/null
return $?
}
funB()
{
ls -e &> /dev/null
return $?
}
funC()
{
true
return $?
}
taskNames=("task 1" "task 2" "task 3")
taskMessages=("performing task 1" "performing task 2" "performing task 3")
tasks=("funA" "funB" "funC")
progress=0
taskpercentage=33
errors=()
for i in ${!tasks[@]}; do
${tasks[i]}
if [[ $? != 0 ]]; then
errors+=(${taskNames[$i]})
fi
progress=$(expr $progress + $taskpercentage)
done
echo ${errors[@]}
exit 0
Now, I need to pipe the loop to zenity so I can show the user a progress bar. Something like this:
(
progress=0
taskpercentage=33
errors=()
for i in ${!tasks[@]}; do
echo "# ${taskMessages[$i]}"
${funcs[i]}
if [[ $? != 0 ]]; then
errors+=(${taskNames[$i]})
fi
sleep 2
progress=$(expr $progress + $taskpercentage)
echo $progress
done
echo "# All tasks completed"
) |
zenity --progress \
--no-cancel \
--title="Performing all tasks" \
--text="Performing all tasks" \
--percentage=0 \
--height 200 \
--width 500
The problem is, if I wrap my code inside a subshell, I lose access to the errors variable. Is there a proper way to do this and keep the changes to error array?
Edit: I do not intend to just print the error array, but to show it to the user through Zenity again, similar to this:
# Show error list
message="Some of the tasks ended with errors and could not be completed."
if [[ ${#errors[@]} > 0 ]]; then
zenity --list --height 500 --width 700 --title="title" \
--text="$message" \
--hide-header --column "Tasks with errors" "${errors[@]}"
fi
Upvotes: 2
Views: 429
Reputation: 17041
If all you need to do is print the error message, you can put it on a separate file descriptor or in a separate file. The most readable way I know of us to use a temporary file:
tempname=$(mktemp) # Create a zero-length file
(
# ... your subshell
if [[ ${#errors[@]} -gt 0 ]]; then # save all $errors entries to the
printf '%s\n' "${errors[@]}" > "$tempname" # file called $tempname
fi
) | zenity # ... your progress code
# After the zenity call, report errors
if [[ -s $tempname ]]; then # -s: size > 0
message="Some of the tasks ended with errors and could not be completed."
zenity --list --height 500 --width 700 --title="title" --text="$message" \
--hide-header --column "Tasks with errors" < "$tempname"
fi # Provide the saved errors to the dialog ^^^^^^^^^^^^^
rm -f "$tempname" # always remove, since mktemp creates the file.
Edit:
All the error
entries can be printed, separated by newlines, using printf
per this answer (another option).
[[ -s $tempname ]]
checks whether the file called $tempname
exists and has a size greater than zero. If so, it means there were some errors, which we saved to that file.
Per the Zenity list-dialog documentation,
Data can be provided to the dialog through standard input. Each entry must be separated by a newline character.
So, zenity --list ... < "$tempname"
provides the items that were formerly in ${errors[@]}
, and that were saved to the temporary file, to the list dialog.
Alternative: You can also move information through the pipeline with, e.g., 2>&3 and the like, but I am not confident enough in my bash hackery to try that right now. :) Here is a related question and a detailed walkthrough of bash redirection.
Upvotes: 3