捕获bash exec I / O重定向中的错误输出

时间:2015-01-03 23:35:23

标签: bash shell tcp io-redirection

我想使用/dev/tcp/host/port psuedo - device syntax在bash中打开TCP套接字,但如果host/port端点没有侦听,我需要优雅地恢复。如果我正在做的就是将数据发送到套接字或从中提取数据,这很容易,因为我只能使用一次性重定向,即:

echo 'ping' 2> >(logger) >/dev/tcp/127.0.0.1/8080

或者,从插座中读取:

cat 2> >(logger) </dev/tcp/127.0.0.1/8080

其中logger是将stdin中的行写入syslog的标准logger

问题是在某些情况下我需要向套接字写一个请求并获得响应。所以我需要用exec打开套接字的文件描述符,但在这种情况下,捕获“-bash:connect:Connection refused”错误更难,因为我不想重定向所有输出shell,这是2> >(logger)在exec上下文中使用时的作用。如果端点关闭,则以下工作很有效(因为bash在打开套接字时遇到错误,并重置所有重定向),但如果能够建立连接,则渲染我的shell非常无用。

exec 2> >(logger) 3<>/dev/tcp/127.0.0.1/8080

到目前为止,我提出的最佳解决方案如下,我打开一个指向原始STDERR的文件描述符(fd 9),将STDERR(fd 2)重定向到我的记录器,打开fd上的套接字3,然后将fd 2设置回原来的STDERR,并关闭我的临时STDERR别名(fd 9)。

exec 9>&2 2> >(logger) 3<>/dev/tcp/127.0.0.1/8080 2>&9 9>&-

对于这么简单的事情来说,这似乎是很多工作。有没有办法告诉bash我想在bash运行exec命令时重定向STDERR,而不是将重定向视为exec的文字参数?


请保留您的答案/建议仅限于bash (最高为bash 4.3.30)。我知道telnetnetcatsocat等等。我正在努力的project(这个bash问题出现的地方)的想法源于对慢一个特定的tool,这是由于它如何将所有shell助手代理到外部(python)解释器。另外,如果可能的话,我想避免使用mkfifo

1 个答案:

答案 0 :(得分:1)

eval 'exec 3<>/dev/tcp/127.0.0.1/8080' 2> >(logger)

或更好,因为它不会破坏旧的文件描述符3:

eval 'exec {fd}<>/dev/tcp/127.0.0.1/8080' 2> >(logger)

使用最小的空闲文件描述符并将其分配给fd。

unset fd
eval 'exec {fd}<>/dev/tcp/127.0.0.1/8080' 2> >(logger)

if test $? != 0 # status of the last command - 0 if the connection succeeded
then
   echo cannot open connection >&2
fi

# $? shows the last status only. Later you can check success this way:

if test -z "$fd"
then
   echo could not open connection >&2 # past tense because it's later now
else
   echo some data to transmit >&$fd
   IFS= read -r just_on_line_of_response <&$fd
fi

完成后,使用

删除连接
exec {fd}>&-

这也可行:

eval "exec $fd>&-"

但是这个失败了,加上关闭你的标准:

exec $fd>&-