Bash:抑制后重新打开 stderr

Bash:抑制后重新打开 stderr

我制作了这个脚本来自动安装/卸载 git。在测试 git 是否已安装的函数中,我使用该git --version命令并测试返回代码。

我不喜欢正常发生的 stderr 输出,因为我试图制作一个不错的自定义输出。虽然我已经弄清楚如何仅针对此功能抑制 stderr,但我似乎无法重新激活它。

调用此函数后,我的read提示消失了。

function CheckGit() {
    exec 3>&2           # link file desc 3 w/ stderr
    exec 2> /dev/null

    SILENT_MODE=$1

    if [[ ! $(git --version) ]]; then
        if [ SILENT_MODE ]; then
            printf "${LT_RED} GIT IS NOT INSTALLED.\n"
        fi
        continue;
    else
        if [ SILENT_MODE ]; then
            printf "${LT_BLUE} GIT IS CURRENTLY INSTALLED.\n"
        fi
        continue;
    fi
    GIT_INSTALLED=$?
    #turn back on the stderr notifications
    exec 2>&3 3>&-      # Restore stdout and close file descriptor #3
}

while true; do
    printf "${LT_BLUE} Menu\n"
    printf " ***********************************************\n"
    printf "${LT_GREEN} a) Check git.\n"
    printf "${LT_GREEN} b) (More to be added)\n"
    printf "${LT_GREEN} c) ...\n"
    printf "${LT_GREEN} d) ...\n"
    printf "${LT_GREEN} h) ...\n"
    printf "${LT_RED} x) Exit.\n"
    printf "\n${NC}"
    read -p "Please make a selection: " eotuyx
    case $eotuyx in
        [Aa]* ) CheckGit true; continue;;
        [Bb]* ) ...; continue;;
        [Cc]* ) ...; continue;;
        [Dd]* ) ...; continue;;
        [Hh]* ) ...; continue;;
        [XxQq]* ) break;;
        * ) -e "\n${NC}" + "Please answer with a, b, c, d, x(or q).";;
    esac
done

答案1

重申所给出的建议在评论中:

  1. continue从函数中删除语句CheckGit
    • 它们没有必要,
    • 而且——您可能没有意识到——它们不仅会导致立即返回(从函数)到主循环,还会立即返回到while true主循环顶部的语句。因此,作为托马斯指出,你的exec 2>&3 3>&-语句没有被执行。

一般注意事项:

  1. if [ SILENT_MODE ]总是正确的,因为莫斯维指出,因为它只是测试字符串是否SILENT_MODE为非空。你似乎想要if [ "$SILENT_MODE" ]
  2. 但你可能在欺骗自己。  if [ "$SILENT_MODE" ]即使$SILENT_MODEis也是 true false— 它所做的只是测试字符串是否为非空,因此调用CheckGit false 仍然会导致显示信息。
  3. 而且,即使您没有欺骗自己,您也可能会欺骗下周必须维护此脚本的人。是的,那个人可能就是你。您明显的逻辑是“如果处于静默模式,则报告额外信息”。这在逻辑上是倒退的;说if [ "$SILENT_MODE" = false ]或调用变量会更有意义VERBOSE_MODE
  4. $?是非常短暂的。总是这样的结果最近的命令。  所以,如果你这样做
    如果  检查是否安装了git;然后
        printf "GIT 未安装。\n"
    别的
        printf "GIT 当前已安装。\n"
    GIT_INSTALLED = $?
    然后GIT_INSTALLED获取 的退出状态printf。您需要GIT_INSTALLED提前设置。
  5. 您的测试if [[ ! $(git --version) ]]; then不是测试“返回代码”(正如您在问题中所说),而是测试是否将git --version任何内容写入标准输出。这可能就是你想要的。这可能是测试是否git安装的最佳方法。但检查命令的退出状态可能会更好(通常通常更好)。
  6. 风格说明:我发现if-如果“真实”部分在前,陈述更容易理解thenelse你的脚本说
    如果没有安装git
    然后
        说没有安装
    否则(即,如果是不是未安装
        说它已经安装了
    双重否定令人困惑。
  7. 而且,是的;exec 2> /dev/null如果您想抑制连续 42 个语句的标准错误,这很方便。如果您只需要影响单个命令,只需将2> /dev/null (或> /dev/null 2>&1) 放在该命令上,如下所示莫斯维建议

答案2

您的命令看起来不错,但逻辑并不能涵盖所有情况。请注意,当您执行 时continue,描述符不会反转。

还要分析它应该如何工作,以及它实际上是如何工作的:

GIT_INSTALLED=$?

$?是最后执行的命令的退出代码。使用调试来更仔细地查看这一点 ( set -x)。

此外,作为初学者,您将从静态测试脚本中受益匪浅shellcheck.net

相关内容