捕获错误的输出在bash EXEC I / O重定向 [英] Capture output of error in bash exec I/O redirection

查看:242
本文介绍了捕获错误的输出在bash EXEC I / O重定向的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想开在bash TCP套接字,使用的/ dev / TCP /主机/端口 psuedo-的设备语法,但我需要恢复正常,如果主机/端口端点不在听。这是容易的,如果我做的是将数据发送到套接字或从中提取数据,因为我可以只使用一次性的重定向,即:

 回声'平'2  - ; >(记录)GT; /dev/tcp/127.0.0.1/8080

或者,从插座上写着:

 猫2  - ; >(记录器)LT; /dev/tcp/127.0.0.1/8080

其中,记录是标准的记录,从标准输入线写入系统日志。

的问题是,在某些情况下,我需要写入套接字的请求,并得到回一个响应。所以,我需要打开一个文件描述符与 EXEC ,但在这种情况下,攻克了-bash:连接:连接被拒绝的错误是很难的,因为我不想重定向在外壳的所​​有输出,这是什么 2 - ; >(记录)在EXEC的环境中使用时一样。下面的伟大工程,如果端点是(因为庆典命中打开套接字时的错误,并将所有重定向),但呈现我的壳pretty无用的,如果它能够进行连接。

  EXEC 2  - ; >(记录器)3';> /dev/tcp/127.0.0.1/8080

到目前为止,最好的解决办法,我想出了如下,在那里我打开一个文件描述符(FD 9)指向原来的错误,都重定向STDERR(FD 2)我的记录器,打开FD插座3,然后设置FD 2回原来的STDERR,并关闭我的临时STDERR别名(FD 9)。

  EXEC 9个和2 2  - ; >(记录器)3';> /dev/tcp/127.0.0.1/8080 2  - ;和9 -9;&放大器;  - 

这似乎是很多工作的东西那么简单。有没有办法告诉我要重定向STDERR庆典而bash中运行 EXEC 命令,而不考虑重定向作为文字参数 EXEC


请保持你的答案/建议局限于来砸(最多来砸30年3月4日)。我知道远程登录的netcat socat 等。对于我的工作(如使用bash的问题出来)的项目的想法来自挫折产生如何慢特定工具是,这是由于它是如何代理了所有它的外壳佣工关闭外部(蟒蛇)间preters。另外,我想避免 mkfifo子如果可能的话。


解决方案

 评估'EXEC 3';> /dev/tcp/127.0.0.1/8080'2  - ; >(记录仪)

或者,要好得多,因为它不破坏旧文件描述符3:

 评估'EXEC {FD}<> /dev/tcp/127.0.0.1/8080'2  - ; >(记录仪)

它使用最小的自由文件描述符并给它分配于fd。

 取消设置FD
EVALEXEC {FD}<> /dev/tcp/127.0.0.1/8080'2 - ; >(记录仪)如果测试$? !=最后一个命令的0#状态 - 0,如果连接成功
然后
   回声无法打开连接>和2
科幻#$?只显示最后的状态。稍后,您可以检查的成功是这样的:如果测试-z$ FD
然后
   回声无法打开连接>和2#过去式,因为它现在以后
其他
   回应一些数据传输>&安培; $ FD
   IFS =读-r just_on_line_of_response<&安培; $ FD
科幻

一旦完成,使用删除连接

  EXEC {FD}>&安培;  - 

这将工作以及

 评估EXEC $ FD>&放大器;  - 

但失败草草收场加上关闭你的标准输出:

  EXEC $ FD>&安培;  - 

I want to open a TCP socket in bash, using the /dev/tcp/host/port psuedo-device syntax, but I need to recover gracefully if the host/port endpoint is not listening. This is easy if all I'm doing is sending data to the socket, or pulling data from it, since I can just use one-off redirection, i.e.:

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

Or, reading from the socket:

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

Where logger is the standard logger that writes lines from stdin to syslog.

The problem is that in some cases I need to write a request to the socket and get a response back. So I need to open a file descriptor for the socket with exec, but in this case, capturing the "-bash: connect: Connection refused" error is harder, since I don't want to redirect all output in the shell, which is what 2> >(logger) does when used in the context of exec. The following works great if the endpoint is down (since bash hits an error when opening the socket, and resets all redirections), but renders my shell pretty useless if it is able to make the connection.

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

So far, the best solution I've come up with is the following, where I open a file descriptor (fd 9) pointing to the original STDERR, redirect STDERR (fd 2) to my logger, open the socket on fd 3, then set fd 2 back to the original STDERR, and close my temporary STDERR alias (fd 9).

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

Which seems like a lot of work for something so simple. Is there a way to tell bash that I want to redirect STDERR while bash runs the exec command, instead of considering the redirection as a literal argument to exec?


Please keep your answers / suggestions limited to bash (up to bash 4.3.30). I know about telnet, netcat, socat, etc. The idea for the project I'm working on (where this bash issue came up) arose from frustration at how slow a particular tool is, which is due to how it proxies all of its shell helpers off to external (python) interpreters. Also, I'd like to avoid mkfifo if possible.

解决方案

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

or, much better because it does not destroy the old file descriptor 3:

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

which uses the smallest free file descriptor and assigns it to 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

Once you are done, delete the connection using

exec {fd}>&-

This will work as well:

eval "exec $fd>&-"

But this fails miserably plus closes your stdout:

exec $fd>&-

这篇关于捕获错误的输出在bash EXEC I / O重定向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆