所以我现在已经摆弄了好几个小时了。我有以下问题:
我正在运行一个写入stdout
via的命令(node.js 脚本) process.stdout.write
。它是交互式的,并且在某一时刻它会退出。
我需要退出结果,因此我创建了一个子 shell,但我还需要它在父 shell 上处于活动状态,因此我将输出重定向到父 shell,如下所示:
exec 4>&1; res=$(exec 3>&1 1>&4; node test.js)
该命令背后的想法是什么?
1>&4
确保节点 test.js 的输出将发送到主(父)shell。我3>&1
打开另一个管道,以便能够将进程的结果写入子 shell,以便我可以将其放入$res
.
示例(伪代码):
//node.js script:
process.stdout.write('write to parent shell because 1>&4')
writeToPipe('/dev/fd/3', 'write the RESULT to subshell so that we can have it in the $res variable')
现在有什么问题吗?
问题是(可能是由于我的侧 shell/unix 方面的误解)我不想简单地写入,因为如果其他人也在/dev/fd/3
写入怎么办?/dev/fd/3
我认为这不是一个很好的实现,只是简单地打开fd/3
并使用它。如果有人调用我的多个进程并且它们发生冲突怎么办?
我如何尝试解决它
我想我可以做这样的事情:
tmppipe=$(mktemp -u)
mkfifo "$tmppipe"
因为我每次都可以生成一个唯一的命名管道并避免冲突。
问题是我无法让它发挥作用。以“微不足道的替代”的方式,我一开始尝试这样做:
exec 4>&1; res=$(exec "$tmppipe">&1 1>&4; node test.js)
但这是行不通的。我认为它不适用于命名管道的这种语法,但我得到的是终端告诉我存在权限问题并且它退出。
答案1
我相信您打算使用管道和文件描述符进行操作,以便test.js
与用户进行某种形式的交互式对话。
例如,您可以使用标准输出test.js
向用户提问,然后用户对标准输入进行答复。由于test.js
程序需要以某种方式在标准输出上提供其最终输出,因此为了将数据提供给命令替换,您需要组织文件描述符 3 连接到替换中的标准输出,并将最终输出写入到该描述符中test.js
。
这有点尴尬。
处理不属于工具最终输出的交互式用户对话(即交互式问题、诊断错误消息、进度条等)的普遍接受的方法是将它们输出到标准错误流上。默认情况下,这将导致这些消息直接发送到终端(假设没有设置文件描述符 2 的重定向),因此它们不会是通过命令替换捕获的结果或通过管道等发送的结果。
这就是 shell 和许多其他工具的工作原理。 shell 会提示标准错误。 shell在标准错误上bash
写入其select
语句输出(一种菜单),命令在标准错误流上read -p 'text'
打印text
以提示用户,并且(显然)它在标准错误上输出错误消息。
所以,你的代码可以简化为
res=$(node test.js)
wheretest.js
将在标准错误流上与用户交互,在标准输入流上读取用户的输入,最后在标准输出流上生成一些输出,这些输出应存储在res
shell 的变量中。
在 shell 中的一个简短演示bash
:
res=$( read -p 'enter something: '; printf 'You entered "%s"\n' "$REPLY" )
printf '"$res" is now "%s"\n' "$res"
res
will的最终值不是enter something:
包含该实用程序写入标准错误流后的字符串read
。