我有这一行:
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
在脚本的顶部 - 如果连接被拒绝,一切都会停止 - 如果在像上面这样的特定行上出现错误,我怎样才能防止这种停止?
所以我有两个目标:
摆脱错误消息,因为这是预期的,我不需要我的图书馆用户看到它。
忽略预期的错误,如果可能的话,我仍然想使用 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
.