我正在编写一个围绕Docker和nsenter
的Ruby包装器。我的工具提供的命令之一是在容器中启动Bash shell。目前,我这样做:
payload = "sudo nsenter --target #{pid(container_name)} --mount --uts --ipc --net --pid -- env #{env} /bin/bash -i -l;"
Kernel.exec(payload)
在Ruby中,Kernel#exec
依赖于exec(2)
系统调用,因此没有fork。
一个问题是容器有时会过早死亡,这会有效地杀死我新创建的Bash提示符。然后我回到最初用于运行我的Ruby工具的提示,但我看不到我正在输入的内容,tty似乎已经破坏并且有效地运行重置可以解决问题。
如果我执行的程序崩溃,我想有条件地运行reset
。我发现以下效果很好:
$ ./myrubytool || reset
除非我想避免强迫每次使用我的工具的人追加|| reset
。
我尝试了以下内容:
payload ="(sudo nsenter --target#{pid(container_name)} - mount --uts --ipc --net --pid - env#{env} / bin / bash -i -l)||复位;"
但这令人惊讶地将reset
置于后台(即我可以通过输入fg
来重置)。一个好处是tty工作正常,但它并不是很理想。
你有什么想法解决这个问题吗?
答案 0 :(得分:0)
如果在终端中禁用了终端回声,则可以运行命令stty echo
以重新启用终端回声。(相反,stty -echo
禁用终端回声,stty -a
显示所有终端设置。)
即使已经启用了终端回声,也可以安全运行,所以如果你想安全地播放它,你可以做./myrubytool ; stty echo
这样的事情,如果它被禁用,它会重新启用终端回声而不管退出Ruby程序的状态。如果您愿意,可以将它放在shell脚本中。
可能有一种方法在Ruby程序退出时执行命令(通常称为"陷阱"),但我不熟悉Ruby以了解是否存在这样的能力。
但是,如果您要创建一般用途的脚本,您可能应该研究更强大的技术,而不是依赖于解决方法。
答案 1 :(得分:0)
这个怎么样?它应该完全符合你的要求
它在一个单独的进程中运行该命令,等待它,如果在完成时,返回值不为0,则它运行命令reset
。
payload = "sudo nsenter --target #{pid(container_name)} --mount --uts --ipc --net --pid -- env #{env} /bin/bash -i -l;"
fork { Kernel.exec(payload) }
pid, status = Process.wait2
unless status.exitstatus == 0
system("reset")
end
修改强>
如果您只想重新开启回声,请将system("reset")
行更改为system("stty echo")
。