将特定编号的Bash文件描述符流转换为变量

时间:2015-05-05 11:56:33

标签: linux bash shell unix sh

我正在尝试将特定编号的文件描述符流式传输到Bash中的变量中。我可以使用以下函数从正常标准执行此操作,但是,如何从特定文件描述符执行此操作。如果我使用相同的方法,我需要将FD引导到子shell中。我总是可以逐行阅读,但是,如果我可以连续播放,那么这将是非常可取的。

我的功能是:

(Math.max.apply(Math, Object.keys(npc_objects))+1);

是的,我知道这不会正常工作,因为管道的末端会丢失(由于它在子shell中执行),但是,在Bash 4 streamStdInTo () { local STORE_INvar="${1}" ; shift printf -v "${STORE_INvar}" '%s' "$( cat - )" } 的上下文中在与开始相同的shell中执行管道结束的方法,或者通过不同的文件描述符指向我希望能够使用它。

所以,我的问题是,我如何使用上述但使用不同于正常的文件描述符?

2 个答案:

答案 0 :(得分:3)

你的意思并不完全清楚,但也许你正在寻找类似的东西:

cat - <&4  # read from fd 4

或者,只需使用重定向调用当前函数:

streamStdInTo foo <&4

编辑: 解决评论中的一些问题,您可以使用fifo:

#!/bin/bash

trap 'rm -f $f' 0
f=$(mktemp xxx)
rm $f
mkfifo $f
echo foo > $f &
exec 4< $f
cat - <&4
wait 

答案 1 :(得分:1)

我认为对于你究竟想做什么有很多困惑。如果我理解正确,这里的最终目标是运行管道并捕获变量中的输出,对吧?有点像这样:

var=$(cmd1 | cmd2)

除了我猜这里的想法是“$ var”的名字存储在另一个变量中:

varname=var

通过使用流程替换,您可以围绕Bash的常规作业控制情况进行最终运行。所以不是这个普通的管道(在ksh或zsh中工作,但在bash中不工作,除非你设置了lastpipe):

cmd1 | cmd2 | read "$varname"

您将使用此命令,该命令与shell处理作业的方式相同:

read "$varname" < <(cmd1 | cmd2)

使用进程替换,“read $ varname”不会在管道中运行,因此Bash不会派生它来运行它。 (当然,你也可以使用你的streamStdInTo()函数)

据我了解,您希望使用数字文件描述符解决此问题:

cmd1 | cmd2 >&$fd1 &
read "$varname" <&$fd2

要创建将管道后台作业连接到“读取”命令的文件描述符,您需要的是管道或fifo。这些可以在不触及文件系统的情况下创建(shell会一直这样做!)但是shell并没有直接暴露这个功能,这就是为什么我们需要诉诸 mkfifo < / strong>创建命名管道。命名管道是文件系统上存在的特殊文件,但是您写入的数据不会进入磁盘。它是存储在内存(管道)中的数据队列。打开文件系统后,它不需要保留在文件系统上,也可以立即删除它:

pipedir=$(mktemp -d /tmp/pipe_maker_XXXX)
mkfifo ${pipedir}/pipe
exec {temp_fd}<>${pipedir}/pipe         # Open both ends of the pipe
exec {fd1}>${pipedir}/pipe
exec {fd2}<${pipedir}/pipe
exec {temp_fd}<&-                       # Close the read/write FD
rm -rf ${pipedir}                       # Don't need the named FIFO any more

在shell中使用命名管道的一个困难是,尝试打开它们只是为了读取,或者只是为了写入而导致调用阻塞,直到某些东西打开管道的另一端。您可以通过在尝试打开另一端之前在后台作业中打开一端来解决这个问题,或者像我上面那样一次打开两端。

“{fd}&lt; ...”语法动态地将未使用的文件描述符编号分配给变量$ fd,并在该文件描述符上打开文件。它已经存在了ksh多年(自1993年以来?),但在Bash中我认为它只能回到4.1(从2010年开始)。