将管道函数的 return 值存储在 bash 中的正确方法
Proper way to store the return value of a piped function in bash
我有一个函数数组,我在 bash 的循环中调用这些函数。每当这些函数中的一个 returns 出现错误时,我都会跟踪它,并将该函数的名称存储在一个错误数组中以显示给用户。这是当前的工作脚本。
#!/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
现在,我需要将循环通过管道传递给 zenity,以便向用户显示进度条。像这样:
(
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
问题是,如果我将代码包装在子 shell 中,我将无法访问错误变量。有没有正确的方法来执行此操作并保留对错误数组的更改?
编辑:
我不打算只打印错误数组,而是再次通过 Zenity 向用户显示,类似这样:
# 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
如果您需要做的只是打印错误消息,您可以将其放在单独的文件描述符或单独的文件中。我所知道的我们使用临时文件的最易读的方式:
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.
编辑:
可以打印所有 error
条目,用换行符分隔,使用 printf
每 this answer (another option).
[[ -s $tempname ]]
检查名为 $tempname
的文件是否存在且大小是否大于零。如果是这样,则表示存在一些错误,我们已将其保存到该文件中。
根据 Zenity list-dialog documentation、
Data can be provided to the dialog through standard input. Each entry must be separated by a newline character.
因此,zenity --list ... < "$tempname"
将以前在 ${errors[@]}
中并保存到临时文件的项目提供到列表对话框。
备选方案:您还可以通过管道移动信息,例如 2>&3 等,但我对我的 bash 黑客技术没有足够的信心,无法立即尝试。 :) 这是 a related question and a detailed walkthrough of bash redirection.
我有一个函数数组,我在 bash 的循环中调用这些函数。每当这些函数中的一个 returns 出现错误时,我都会跟踪它,并将该函数的名称存储在一个错误数组中以显示给用户。这是当前的工作脚本。
#!/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
现在,我需要将循环通过管道传递给 zenity,以便向用户显示进度条。像这样:
(
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
问题是,如果我将代码包装在子 shell 中,我将无法访问错误变量。有没有正确的方法来执行此操作并保留对错误数组的更改?
编辑: 我不打算只打印错误数组,而是再次通过 Zenity 向用户显示,类似这样:
# 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
如果您需要做的只是打印错误消息,您可以将其放在单独的文件描述符或单独的文件中。我所知道的我们使用临时文件的最易读的方式:
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.
编辑:
可以打印所有
error
条目,用换行符分隔,使用printf
每 this answer (another option).[[ -s $tempname ]]
检查名为$tempname
的文件是否存在且大小是否大于零。如果是这样,则表示存在一些错误,我们已将其保存到该文件中。根据 Zenity list-dialog documentation、
Data can be provided to the dialog through standard input. Each entry must be separated by a newline character.
因此,
zenity --list ... < "$tempname"
将以前在${errors[@]}
中并保存到临时文件的项目提供到列表对话框。
备选方案:您还可以通过管道移动信息,例如 2>&3 等,但我对我的 bash 黑客技术没有足够的信心,无法立即尝试。 :) 这是 a related question and a detailed walkthrough of bash redirection.