我有一个可执行的 ruby 脚本,如下所示:
example
:
#!/usr/bin/env ruby
at_exit do
# Replace the currently running Ruby process with a new instance of the parent shell
exec(`ps -p #{Process.ppid} -o comm=`.chomp)
end
作为命令运行时它工作正常,但由于它用新的 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 的新实例替换自身。 (例外情况是用父 shell 的新实例替换 ruby 脚本的父进程的解决方案,这也足够了)
您想要的可以通过使用您控制的父进程而不是 bash 来实现。
由于
example
脚本将在退出时运行父进程,因此如果您控制父进程及其功能,您就可以做任何您喜欢的事情。
当前父进程是
bash
。你无法控制 bash,因此一旦将 Ruby 脚本替换为 bash,bash 将“挂起”,等待输入。
我们想要的是创建一个为我们运行
example
脚本的父进程,然后 example
脚本将运行我们的进程 at_exit
,然后我们可以告诉我们的进程退出,让其他一切都可以运行按照您的规格正常继续。
这是一个简单的 C 程序,我们将用作父进程。我们姑且称之为
runner.c
:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char* argv[]) {
// This is the magic trick which will prevent an infinite loop.
// Once the Ruby script launches runner.c without arguments, we just exit.
if (argc == 1) {
printf("Exit\n");
exit(0);
}
// In order to be the parent for the Ruby script, we need to launch it as the child:
if (fork() == 0){
printf("I'm the child process.\n");
// Run the example script as a child of the runner.c process
// NOTE: You may need to adjust the Ruby path here
execl("/usr/bin/ruby", "ruby", "example", (char *) 0);
exit(0);
} else {
printf("I'm the parent.\n");
// Wait here for the Ruby script to execute (wait for all children to exit).
while (wait(NULL) > 0);
}
printf("runner.c is done.\n");
return 0;
}
现在编译:
gcc -o runner runner.c
然后像这样运行:
./runner dummy_arg
它应该按照您的意愿工作,使 Ruby 脚本正常退出。 现在你可以重写
test.sh
:
#!/usr/bin/bash
./runner dummy_arg && echo "How do i get here"
一切都应该有效。