摆脱 bash 脚本中的“连接被拒绝”错误

摆脱 bash 脚本中的“连接被拒绝”错误

我有这一行:

exec 3<>/dev/tcp/127.0.0.1/9091 > /dev/null 2>&1 ||  { PORT_IS_FREE="yes"; };

它正在检查端口 9091 是否可用。如果无法建立连接,则会出现以下错误:

my-script: connect: Connection refused
my-script: line 6: /dev/tcp/127.0.0.1/9091: Connection refused

当然,这个错误并不是坏消息,它意味着该端口是空闲的。如何防止错误跟踪被记录?我尝试将 stdout/stderr 发送到 /dev/null,但显然这不起作用。

奖金:

set -e在脚本的顶部 - 如果连接被拒绝,一切都会停止 - 如果在像上面这样的特定行上出现错误,我怎样才能防止这种停止?

所以我有两个目标:

  1. 摆脱错误消息,因为这是预期的,我不需要我的图书馆用户看到它。

  2. 忽略预期的错误,如果可能的话,我仍然想使用 set -e 。

答案1

要继续使用set -e但仍然允许已知错误,请使用以下咒语:

/bin/false || :

这使用||操作符来“消耗”错误,以便将其视为对set -e活动环境来说是非致命的。

您已经在使用2>/dev/null来抑制标准错误,所以您确定错误来自您在此处引用的行吗?另外,exec我建议不使用 ,而是使用更具可读性的替代方案:

if ! nc -z localhost 9091 1> /dev/null 2>&1; then
    port_free="yes"
fi

由于 的返回码nc是由if语句检查的,因此在 后也是安全的set -e

答案2

为了正确地将错误和输出流重定向到 /dev/null,从而抑制错误消息,您需要对整个 exec 命令进行分组:

{ exec 3<>/dev/tcp/127.0.0.1/9091; } > /dev/null 2>&1 || PORT_IS_FREE="yes"

exec是一个 shell 内置函数,所以我很难预测它会如何表现,但是我假设即使它能够特殊处理<>整个操作仍然分几个步骤进行,只有最后一个的流哪个被重定向。对 的工作原理有更多了解的人exec也许能够对此有所了解。

编辑:我不知道为什么你需要对变量赋值进行括号分组,因为它是一个单独的命令,但是如果你愿意的话,你仍然可以将括号与我的示例结合使用,而不是我使用的裸赋值。

至于忽略错误,您可以在重定向后终止命令,而;不是通过以下方式使用其退出状态||

{ exec 3<>/dev/tcp/127.0.0.1/9091; } > /dev/null 2>&1 ; PORT_IS_FREE="yes"

当然,在这种情况下,存在的问题是您也无法捕获任何其他错误。我刚刚尝试过,发生相关错误后退出状态为 1。如果在不同的错误上返回其他代码(我实际上对此表示怀疑,因为 1 是一个非常通用的错误代码),您可以测试 1。 编辑:此解决方案还具有在 , 之后返回代码 1 时不退出的好处exec,何时set -e使用:

{ exec 3<>/dev/tcp/127.0.0.1/9091; } > /dev/null 2>&1 || [ "$?" = 1 ] && PORT_IS_FREE="yes"

否则,您可以grep尝试匹配错误消息,我认为这更可靠:

socketOpenOutput="$({ exec 3<>/dev/tcp/127.0.0.1/9091; } 2>&1`)"
socketOpenErrorCode="$?"
if [ "$socketOpenErrorCode" != 0 ]; then
    if ! echo "$socketOpenOutput" | grep 'connect\s*:\s*Connection refused' >/dev/null; then
        echo "An unexpected error happened when opening the socket!"
        exit 1
    fi
fi

PORT_IS_FREE="yes"

然而,这个并不能很好地与set -e.

相关内容