(OSX 10.7)我们使用的应用程序让我们分配在应用程序中发生某些活动时要调用的脚本。我已经分配了一个bash脚本并且正在调用它,问题是我需要做的是执行一些命令,等待30秒,然后再执行一些命令。如果我的bash脚本执行“睡眠30”,整个应用程序会在等待我的脚本完成时冻结30秒。
我尝试将30秒等待(和第二组命令)放入一个单独的脚本并调用“./secondScript&”但应用程序仍然在那里停留30秒无所事事。我假设应用程序正在等待脚本和所有子进程终止。
我已经尝试过这些变体来从主脚本中调用第二个脚本,它们都有同样的问题:
我无法更改应用程序并告诉它启动我的脚本而不是等待它完成。
如何启动流程(我希望流程采用脚本语言),以使新流程不是当前流程的子流程?
谢谢, 克里斯
P.S。我尝试了“disown”命令,它也没有帮助。我的主要脚本如下所示:
[initial commands]
echo Launching second script
./secondScript &
echo Looking for jobs
jobs
echo Sleeping for 1 second
sleep 1
echo Calling disown
disown
echo Looking again for jobs
jobs
echo Main script complete
我输出的是:
Launching second script
Looking for jobs
[1]+ Running ./secondScript &
Sleeping for 1 second
Calling disown
Looking again for jobs
Main script complete
此时调用应用程序在那里停留45秒,等待secondScript完成。
p.p.s
如果在主脚本的顶部,我执行“ps”,它返回的唯一内容是我在单独的终端窗口中打开的交互式bash会话的进程ID。
$ SHELL的值是/ bin / bash
如果我执行“ps -p $$”,它会正确告诉我
PID TTY TIME CMD
26884 ?? 0:00.00 mainScript
如果我执行“lsof -p $$”,它会给我各种结果(我没有在这里粘贴所有列,假设它们不相关):
FD TYPE NAME
cwd DIR /private/tmp/blahblahblah
txt REG /bin/bash
txt REG /usr/lib/dyld
txt REG /private/var/db/dyld/dyld_shared_cache_x86_64
0 PIPE
1 PIPE -> 0xffff8041ea2d10
2 PIPE -> 0xffff 8017d21cb
3r DIR /private/tmp/blahblah
4r REG /Volumes/DATA/blahblah
255r REG /Volumes/DATA/blahblah
答案 0 :(得分:23)
在Unix中执行此操作的典型方法是双叉。在bash中,您可以使用
执行此操作( sleep 30 & )
(..)
创建一个子进程,&
创建一个孙进程。当子进程终止时,孙进程由init继承。
如果这不起作用,那么您的应用程序不会等待子进程。
它可能正在等待的其他事情包括会话和打开锁定文件:
要创建新会话,Linux有一个setsid
。在OS X上,您可以通过script
执行此操作,这偶然也会创建一个新会话:
# Linux:
setsid sleep 30
# OS X:
nohup script -q -c 'sleep 30' /dev/null &
要查找继承的文件描述符列表,可以使用lsof -p yourpid
,它将输出如下内容:
sleep 22479 user 0u CHR 136,32 0t0 35 /dev/pts/32
sleep 22479 user 1u CHR 136,32 0t0 35 /dev/pts/32
sleep 22479 user 2u CHR 136,32 0t0 35 /dev/pts/32
sleep 22479 user 5w REG 252,0 0 1048806 /tmp/lockfile
在这种情况下,除了标准FD 0,1和2之外,还有一个fd 5打开一个父文件可以等待的锁定文件。
要关闭fd 5,您可以使用exec 5>&-
。如果您认为锁定文件本身可能是stdin / stdout / stderr,则可以使用nohup
将它们重定向到其他位置。
答案 1 :(得分:12)
另一种方法是放弃孩子
#!/bin/bash
yourprocess &
disown
据我所知,该应用程序取代了普通的bash shell,因为即使init
应该处理这个子进程,它仍在等待进程完成。
可能是“应用程序”拦截了通常由init
完成的孤儿处理。
在这种情况下,只有一些IPC的并行流程才能提供解决方案(参见我的其他答案)
答案 2 :(得分:11)
我认为这取决于您的父进程如何尝试检测您的子进程是否已完成。 在我的情况下(我的父进程是gnu make),我成功通过关闭stdout和stderr(稍微基于answer of that other guy)这样:
sleep 30 >&- 2>&- &
您也可以关闭stdin
sleep 30 <&- >&- 2>&- &
或另外拒绝您的子进程(不适用于Mac)
sleep 30 <&- >&- 2>&- & disown
目前仅在kubuntu 14.04和Mac OSX上使用bash进行测试。
答案 3 :(得分:1)
如果一切都失败了:
创建命名管道
从“应用程序”启动“慢”脚本独立,确保在无限循环中执行它的任务,从管道读取开始。它在尝试阅读时会被读取阻止..
,启动您的其他脚本。当需要调用“慢”脚本时,只需将一些数据写入管道即可。慢速脚本将以独立开始,因此您的脚本不会等待“慢”脚本完成。
所以,回答这个问题:
bash - 如何启动一个不属于原始流程的新流程?
简单:不要启动它,而是让一个独立的实体在启动期间启动它...如init
或使用命令at
或batch
答案 4 :(得分:0)
这里我有一个shell
└─bash(13882)
我开始这样的流程:
$ (urxvt -e ssh somehost&)
我得到了一个进程树(此输出从pstree -p
剪断):
├─urxvt(14181)───ssh(14182)
这个过程在pid 1(我的情况下为systemd
)下是父级的。
但是,如果我这样做了(注意&
所在的位置):
$ (urxvt -e ssh somehost)&
然后该进程将成为shell的子进程:
└─bash(13882)───urxvt(14181)───ssh(14182)
在这两种情况下都会立即返回shell提示符,我可以exit
没有终止我上面开始的进程树。
对于后一种情况,进程树在pid 1下面进行重新分配 shell退出,因此最终与第一个示例相同。
├─urxvt(14181)───ssh(14182)
无论哪种方式,结果都是一个比shell更长的进程树。该 唯一的区别是该进程树的初始父级。
供参考,您也可以使用
nohup urxvt -e ssh somehost &
urxvt -e ssh somehost & disown $!
两者都提供与上面第二个例子相同的流程树。
└─bash(13882)───urxvt(14181)───ssh(14182)
当shell被终止时,进程树像以前一样被重新分配 给pid 1。
nohup
还将进程的标准输出重定向到文件
nohup.out
所以,如果这是一个有用的特性,那么它可能是一个更有用的选择。
否则,使用上面的第一个表单,您会立即拥有一个完整的表单 分离的过程树。