You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用进程替换时`heroku run`命令会无限挂起?

为什么cat <( heroku run -a my-app echo hello )会无限挂起?

这事儿得从bash进程替换的机制和heroku run的行为逻辑说起,咱们一步步拆解:

1. 进程替换的本质

bash的<(command)语法会创建一个匿名管道(或FIFO),让command把输出写到管道的一端,再让前面的命令(这里是cat)从另一端读取。但有个关键细节:这个command子进程的stdin会直接继承父bash的stdin——也就是你的终端窗口。

2. heroku run的“小特性”

哪怕你指定了要执行echo hello,heroku run默认会把本地的stdin/stdout/stderr绑定到远程Heroku dyno的会话。当它检测到stdin是终端(tty)时,执行完你指定的命令后,它不会立刻退出——而是会保持连接,等着你输入更多命令。

这就导致了死锁:

  • heroku run进程一直挂着,没关闭它的stdout(也就是进程替换管道的写端);
  • cat一直在等管道的EOF(结束信号),但因为heroku run没退出,写端始终打开,cat就只能无限等待下去。

3. 为什么其他命令没问题?

  • cat <( echo hello ):echo是个简单命令,它根本不会读取stdin,执行完就直接退出,管道写端关闭,cat读完输出就结束了。
  • heroku run -a my-app echo hello | cat:管道里的heroku run的stdin是管道的读端(不是终端),当它尝试读取stdin时,会直接得到EOF(因为管道的写端没有进程在写),所以执行完echo hello就立刻退出,cat自然能正常拿到输出。

4. 为什么--no-tty没用?

--no-tty只是让heroku run不给dyno分配伪终端,但它还是会尝试读取stdin。只要stdin是终端(进程替换场景下就是这样),它依然会等着输入,不会自动退出。

解决办法

核心思路就是让heroku run别等着stdin输入,最简单的方式是把它的stdin重定向到/dev/null:

cat <( heroku run -a my-app echo hello < /dev/null )

这样heroku run检测到stdin没有输入来源,执行完命令就会立刻退出,管道写端关闭,cat就能正常读取输出并结束了。

内容的提问来源于stack exchange,提问作者keturn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:29:55