命名管道不会等到在 bash 中完成

Posted

技术标签:

【中文标题】命名管道不会等到在 bash 中完成【英文标题】:Named pipe does not wait until completion in bash 【发布时间】:2018-01-29 22:09:12 【问题描述】:

在下面的 test.jl 中创建一个 output.txt 并生成一些控制台输出。控制台输出处理得很好。但是在完全创建 output.txt 之前,控制权会在 echo 之后立即返回。在 echo 和 mv 之间放置一个等待会导致无限期的等待。是否应该在不终止管道的情况下将回车传递给管道?

mkfifo pipe
sleep 1000000 > pipe &
julia <pipe >stdout.txt 2>stderr.txt &

echo "include(\"test.jl\")" > pipe
mv output.txt temp/
echo "include(\"test2.jl\")" > pipe

谢谢!

【问题讨论】:

您要求julia 在后台创建文件,然后立即尝试移动它。这是一个竞争条件。你需要找到一种方法来等待它。方法包括为每个实例运行一个julia 实例,以便您可以等待进程退出,让程序将一些内容记录到您可以定期检查的 stdout.txt 中,猜测它需要不到 60 秒并休眠这么长,或者在完成后让test.jl 自己移动文件。 想一想如果行为与此不同会产生什么影响,并且程序必须等待其写入的内容在下游完全处理,然后才能从写入操作中重新获得控制权——如果你是运行find 管道进入xargs rm,它无法继续找到第二个文件,直到第一个文件被完全删除。当此类处理完成时,您需要提出一套全新的流量控制结构来进行通信——您将获得什么价值? 【参考方案1】:

我知道test.jltest2.jl 都写入output.txt,因此您必须在运行test2.jltest2.jl 之前将文件移动到另一个目录@ 预计output.txttemp/ 目录中,你有在text2.jl 运行之前将其移动到那里。

如果是,那么下面的代码应该可以解决问题:

mkfifo pipe
sleep 1000000 > pipe &
julia <pipe >stdout.txt 2>stderr.txt &

echo "include(\"test.jl\")" > pipe
echo "mv(\"output.txt\", \"temp/\")" > pipe
echo "include(\"test2.jl\")" > pipe

Julia 以这种方式运行mv 命令,并确保它在test.jl 之后但在test2.jl 之前执行。

但实际上我们已经到了编写一个名为 e.g. 的 Julia 脚本会更好的地步。 script.jl:

include("test.jl")
mv("output.txt", "temp/")
include("test2.jl")

并使用julia script.jl 运行它。

【讨论】:

保留 OP 的 sleep hack 是不幸的。考虑将其替换为 (after julia 调用) exec 3&gt;pipe,然后在输出端使用 &gt;&amp;3 执行 echos;这样,只有一个用于管道输入端的文件描述符保持打开状态,而不是让其上的 FD 数量随时间变化。 有没有更好的方法让命名管道保持打开状态,这样 Julia 在第一个 echo 之后就不会收到 EOF?我们假设一个交互式会话 - 而不是脚本 - Julia 在后台运行。 我在上述评论中建议的方法就是这样做的。 exec 3&gt;pipe 在交互式会话中完全有效。 谢谢。我在并行写作。 (当你确实想关闭管道时,顺便说一下,你可以用exec 3&gt;&amp;-来做到这一点。

以上是关于命名管道不会等到在 bash 中完成的主要内容,如果未能解决你的问题,请参考以下文章

为啥 bash 在写入命名管道时关闭?

在 bash 中打开命名管道,而不读取或写入它

可能的竞争条件,来自多个 tee 接收者的管道输出在 BASH 脚本中的命名管道上无序到达

处理命名管道时,fish shell 和 bash 有啥区别?

BASH 命名管道锁定

sh 等效于从命名管道读取的 bash 命令