为何使用进程替换时`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
相关产品推荐
相关产品推荐

