【问题标题】:Proper way to store the return value of a piped function in bash在 bash 中存储管道函数返回值的正确方法
【发布时间】:2017-04-28 21:30:10
【问题描述】:

我有一个函数数组,我在 bash 的循环中调用它们。每当这些函数中的一个返回错误时,我都会跟踪它将该函数的名称存储在错误数组中以向用户显示。这是当前的工作脚本。

#!/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 中,我将无法访问 errors 变量。是否有适当的方法来执行此操作并保留对错误数组的更改?

编辑: 我不打算只打印错误数组,而是再次通过 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

【问题讨论】:

  • 不需要从函数显式返回状态,默认情况下就是这样做的。

标签: bash subshell zenity


【解决方案1】:

如果您只需要打印错误消息,您可以将其放在单独的文件描述符或单独的文件中。我知道我们使用临时文件的最易读的方式:

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.

编辑:

  1. 所有error 条目都可以打印出来,用换行符分隔,使用printf per this answer (another option)。

  2. [[ -s $tempname ]] 检查名为$tempname 的文件是否存在并且大小是否大于零。如果是这样,则表示存在一些错误,我们将其保存到该文件中。

  3. 根据Zenity list-dialog documentation

    数据可以通过标准输入提供给对话框。每个条目必须用换行符分隔。

    因此,zenity --list ... &lt; "$tempname" 将以前在 ${errors[@]} 中并保存到临时文件中的项目提供给列表对话框。

替代方案:您也可以使用 2>&3 等通过管道移动信息,但我对我的 bash 黑客技术没有足够的信心,现在无法尝试。 :) 这是a related questiondetailed walkthrough of bash redirection

【讨论】:

  • 我需要的错误不是为了打印,而是为了再次通过 zenity 显示。我会试试你有趣的答案。
  • 当然!非常感谢!
  • @derkomai 已编辑 - 看看你的想法!感谢您的问题编辑。
  • 我认为这是一个完美的解决方案。
猜你喜欢
  • 2011-09-08
  • 2021-02-28
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 2023-03-16
  • 2021-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多