命令替换为新Shell进程后,如何继续执行后续脚本?
问题:Ruby脚本替换Shell进程导致Shell脚本后续命令无法执行
我有一个可执行的Ruby脚本example,代码如下:
#!/usr/bin/env ruby at_exit do # 将当前运行的Ruby进程替换为父Shell的新实例 exec(`ps -p #{Process.ppid} -o comm=`.chomp) end
单独运行该脚本时工作正常,但在Shell脚本中调用它时,由于它会将自身进程替换为新的Shell实例,导致Shell脚本里的后续命令无法执行。
我需要修改Shell脚本(通过bash test.sh方式运行),让后续命令能继续执行。
期望实现的示例
test.sh
#!/usr/bin/bash ./example && echo "How do i get here"
test1.sh
#!/usr/bin/bash VAR=foo $VAR ./example <argument>
test2.sh
#!/usr/bin/bash cd ~ && git clone https://github.com/gfxstrand/pycook yes | ./example
test3.sh
#!/usr/bin/bash ./example || echo "How do i get here"
注意:无法修改该Ruby脚本的核心行为——它必须在退出时将自身替换为父Shell的新实例(例外:替换Ruby脚本父进程为父Shell新实例的方案也可接受)。
解决方案:用子Shell隔离Ruby脚本进程
核心思路是让Ruby脚本在子Shell中运行,这样它替换的是子Shell进程,不会影响外层的主Shell脚本进程,后续命令就能正常执行。
修改后的示例脚本
修改后的test.sh
#!/usr/bin/bash (./example) && echo "How do i get here"
修改后的test1.sh
#!/usr/bin/bash VAR=foo ($VAR ./example <argument>)
修改后的test2.sh
#!/usr/bin/bash cd ~ && git clone https://github.com/gfxstrand/pycook (yes | ./example)
修改后的test3.sh
#!/usr/bin/bash (./example) || echo "How do i get here"
原理说明
当用括号()包裹命令时,Bash会创建一个独立的子Shell进程来执行括号内的命令。此时Ruby脚本的父进程是这个子Shell,当Ruby脚本执行exec替换进程时,只会替换子Shell,而主Shell脚本的进程不受任何影响,因此后续命令可以继续执行。
内容的提问来源于stack exchange,提问作者nfl
相关产品推荐
相关产品推荐

