Linux 如何启动一个不是原始进程的子进程的新进程?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20338162/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 01:30:58  来源:igfitidea点击:

How can I launch a new process that is NOT a child of the original process?

linuxbashmacosdaemon

提问by Betty Crokker

(OSX 10.7) An application we use let us assign scripts to be called when certain activities occur within the application. I have assigned a bash script and it's being called, the problem is that what I need to do is to execute a few commands, wait 30 seconds, and then execute some more commands. If I have my bash script do a "sleep 30" the entire application freezes for that 30 seconds while waiting for my script to finish.

(OSX 10.7) 我们使用的一个应用程序让我们分配脚本以在应用程序中发生某些活动时调用。我已经分配了一个 bash 脚本并且它正在被调用,问题是我需要做的是执行一些命令,等待 30 秒,然后再执行一些命令。如果我让我的 bash 脚本执行“sleep 30”,则整个应用程序会在等待我的脚本完成时冻结 30 秒。

I tried putting the 30 second wait (and the second set of commands) into a separate script and calling "./secondScript &" but the application still sits there for 30 seconds doing nothing. I assume the application is waiting for the script and all child processesto terminate.

我尝试将 30 秒等待(和第二组命令)放入一个单独的脚本中并调用“./secondScript &”,但该应用程序仍然在那里停留了 30 秒,什么也不做。我假设应用程序正在等待脚本和所有子进程终止。

I've tried these variations for calling the second script from within the main script, they all have the same problem:

我已经尝试了从主脚本中调用第二个脚本的这些变体,它们都有相同的问题:

  • nohup ./secondScript &
  • ( ( ./secondScript & ) & )
  • ( ./secondScript & )
  • nohup script -q /dev/null secondScript &
  • nohup ./secondScript &
  • ( ( ./secondScript & ) & )
  • ( ./secondScript & )
  • nohup script -q /dev/null secondScript &

I do not have the ability to change the application and tell it to launch my script and not wait for it to complete.

我无法更改应用程序并告诉它启动我的脚本而不是等待它完成。

How can I launch a process (I would prefer the process to be in a scripting language) such that the new process is not a child of the current process?

我如何启动一个进程(我更喜欢该进程使用脚本语言),以便新进程不是当前进程的子进程?

Thanks, Chris

谢谢,克里斯

p.s. I tried the "disown" command and it didn't help either. My main script looks like this:

ps 我尝试了“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

and what I get for output is this:

我得到的输出是这样的:

Launching second script
Looking for jobs
[1]+ Running ./secondScript &
Sleeping for 1 second
Calling disown
Looking again for jobs
Main script complete

and at this point the calling application sits there for 45 seconds, waiting for secondScript to finish.

此时调用应用程序会在那里停留 45 秒,等待 secondScript 完成。

p.p.s

pps

If, at the top of the main script, I execute "ps" the only thing it returns is the process ID of the interactive bash session I have open in a separate terminal window.

如果在主脚本的顶部执行“ps”,它返回的唯一内容是我在单独的终端窗口中打开的交互式 bash 会话的进程 ID。

The value of $SHELL is /bin/bash

$SHELL 的值是 /bin/bash

If I execute "ps -p $$" it correctly tells me

如果我执行“ps -p $$”,它会正确地告诉我

PID   TTY TIME    CMD
26884 ??  0:00.00 mainScript

If I execute "lsof -p $$" it gives me all kinds of results (I didn't paste all the columns here assuming they aren't relevant):

如果我执行“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

回答by that other guy

The typical way of doing this in Unix is to double fork. In bash, you can do this with

在 Unix 中这样做的典型方法是双叉。在 bash 中,您可以使用

( sleep 30 & )

(..)creates a child process, and &creates a grandchild process. When the child process dies, the grandchild process is inherited by init.

(..)创建一个子进程,并&创建一个孙进程。当子进程死亡时,孙进程由 init 继承。



If this doesn't work, then your application is not waiting for child processes.

如果这不起作用,那么您的应用程序没有在等待子进程。

Other things it may be waiting for include the session and open lock files:

它可能正在等待的其他事情包括会话和打开的锁定文件:

To create a new session, Linux has a setsid. On OS X, you might be able to do it through script, which incidentally also creates a new session:

要创建新会话,Linux 有一个setsid. 在 OS X 上,您可能可以通过 来完成script,这顺便也创建了一个新会话:

# Linux:
setsid sleep 30

# OS X:
nohup script -q -c 'sleep 30' /dev/null &

To find a list of inherited file descriptors, you can use lsof -p yourpid, which will output something like:

要查找继承的文件描述符列表,您可以使用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

In this case, in addition to the standard FDs 0, 1 and 2, you also have a fd 5 open with a lock file that the parent can be waiting for.

在这种情况下,除了标准的 FD 0、1 和 2 之外,您还有一个 fd 5 打开,其中包含父级可以等待的锁定文件。

To close fd 5, you can use exec 5>&-. If you think the lock file might be stdin/stdout/stderr themselves, you can use nohupto redirect them to something else.

要关闭 fd 5,您可以使用exec 5>&-. 如果您认为锁定文件可能是 stdin/stdout/stderr 本身,您可以使用nohup将它们重定向到其他内容。

回答by thom

Another way is to abandon the child

另一种方式是抛弃孩子

#!/bin/bash

yourprocess &

disown

As far as I understand, the application replaces the normal bash shell because it is still waiting for a process to finish even if initshould have taken care of this child process. It could be that the "application" intercepts the orphan handling which is normally done by init.

据我了解,该应用程序替换了普通的 bash shell,因为它仍在等待进程完成,即使init应该处理这个子进程。可能是“应用程序”拦截了通常由init.

In that case, only a parallel process with some IPC can offer a solution (see my other answer)

在这种情况下,只有具有某些 IPC 的并行进程才能提供解决方案(请参阅我的其他答案)

回答by thom

If all else fails:

如果一切都失败了:

  1. Create a named pipe

  2. start the "slow" script independentfrom the "application", make sure executes it's task in an endless loop, starting with reading from the pipe. It will become read-blocked when it tries to read..

  3. from the application, start your other script. When it needs to invoke the "slow" script, just write some data to the pipe. The slow script will start independentlyso your script won't wait for the "slow" script to finish.

  1. 创建命名管道

  2. 启动独立于“应用程序”的“慢”脚本,确保在无限循环中执行它的任务,从管道读取开始。当它尝试读取时,它将成为读取阻塞。

  3. 从应用程序中,启动您的其他脚本。当它需要调用“慢”脚本时,只需将一些数据写入管道即可。慢速脚本将独立启动,因此您的脚本不会等待“慢速”脚本完成。

So, to answer the question:
bash - how can I launch a new process that is NOT a child of the original process?

所以,要回答这个问题:
bash - 我如何启动一个不是原始进程的子进程的新进程?

Simple: don't launch it but let an independent entity launch it during boot...like initor on the fly with the command ator batch

简单:不要启动它,而是让一个独立的实体在启动过程中启动它......就像init或在运行中使用命令atbatch

回答by Joe

I think it depends on how your parent process tries to detect if your child process has been finished. In my case (my parent process was gnu make), I succeed by closing stdout and stderr (slightly based on the answer of that other guy) like this:

我认为这取决于您的父进程如何尝试检测您的子进程是否已完成。在我的情况下(我的父进程是 gnu make),我通过关闭 stdout 和 stderr(稍微基于其他人回答)来成功,如下所示:

sleep 30 >&- 2>&- &

You might also close stdin

你也可以关闭标准输入

sleep 30 <&- >&- 2>&- &

or additionally disown your child process (not for Mac)

或另外否认您的子进程(不适用于 Mac)

sleep 30 <&- >&- 2>&- & disown

Currently tested only in bash on kubuntu 14.04 and Mac OSX.

目前仅在 kubuntu 14.04 和 Mac OSX 上的 bash 中进行了测试。

回答by starfry

Here I have a shell

这里我有一个壳

└─bash(13882)

Where I start a process like this:

我在哪里开始这样的过程:

$ (urxvt -e ssh somehost&)

I get a process tree (this output snipped from pstree -p):

我得到一个进程树(这个输出是从 截取的pstree -p):

├─urxvt(14181)───ssh(14182)

where the process is parented beneath pid 1 (systemdin my case).

该进程位于 pid 1 之下(systemd在我的情况下)。

However, had I instead done this (note where the &is) :

但是,如果我改为这样做(请注意它的&位置):

$ (urxvt -e ssh somehost)&

then the process would be a child of the shell:

那么该进程将是 shell 的子进程:

└─bash(13882)───urxvt(14181)───ssh(14182)

In both cases the shell prompt is immediately returned and I can exitwithout terminating the process tree that I started above.

在这两种情况下,shell 提示符都会立即返回,我可以在exit不终止上面启动的进程树的情况下。

For the latter case the process tree is reparented beneath pid 1 when the shell exits, so it ends up the same as the first example.

对于后一种情况,当 shell 退出时,进程树在 pid 1 下重新父级,因此它最终与第一个示例相同。

├─urxvt(14181)───ssh(14182)

Either way, the result is a process tree that outlives the shell. The only difference is the initial parenting of that process tree.

无论哪种方式,结果都是一个比 shell 寿命更长的进程树。唯一的区别是该进程树的初始父级。

For reference, you can also use

作为参考,您也可以使用

  • nohup urxvt -e ssh somehost &
  • urxvt -e ssh somehost & disown $!
  • nohup urxvt -e ssh somehost &
  • urxvt -e ssh somehost & disown $!

Both give the same process tree as the second example above.

两者都给出了与上面第二个示例相同的进程树。

└─bash(13882)───urxvt(14181)───ssh(14182)

When the shell is terminated the process tree is, like before, reparented to pid 1.

当 shell 被终止时,进程树和以前一样,重新指向 pid 1。

nohupadditionally redirects the process' standard output to a file nohup.outso, if that is a useful trait, it may be a more useful choice.

nohup另外将进程的标准输出重定向到文件, nohup.out因此,如果这是一个有用的特征,它可能是一个更有用的选择。

Otherwise, with the the first form above, you immediately have a completely detached process tree.

否则,使用上面的第一种形式,您将立即拥有一个完全分离的进程树。