在子shell中后台运行Bash命令

3

我希望能够在子shell中像不在子shell中一样启动一个进程。

$( sleep 3 & ) 只是忽略了&符号。

我尝试过:

$( sleep 3 & )
$( sleep 3 & ) &
$( sleep 3 ) &

但是什么都没有改变。

然后我尝试了$( disown sleep 3 & ),结果返回:

disown: 无法在子shell中操作作业

这让我尝试使用$( set -m; disown sleep 3 & ),但我得到了相同的输出。

我甚至尝试创建一个C++程序来使其成为守护进程:

#include <unistd.h>
#include <chrono>
#include <thread>
using namespace std;

int main() {
    int ret = fork();
    if (ret < 0) return ret;  // fork error
    if (ret > 0) return 0;  // parent exits

    this_thread::sleep_for(chrono::milliseconds(3000));

    return 0;
}

运行后发现,因为我使用了fork而不是separate_from_parent_and_let_parent_die,子shell仍然会等待进程结束。

为了排除我的MCVE,从子shell调用一个函数,在该函数中,我需要从服务器获取数据并在后台运行。我的唯一限制是不能编辑子shell中的函数调用。

有没有办法在C++程序中不使用fork而是从父进程中分离出来以便可以无影响地结束或强制命令从子shell中分离出来在bash中执行?

最好是后者。


2
你真正想做什么?$(...)用于运行命令并将其输出放入当前shell命令中。如果你在后台运行该命令,如何捕获其输出? - Barmar
2个回答

5
< p > $(...) 命令替代机制会等待与子shell的 stdout 相连的管道上的EOF。所以即使你在子shell中后台运行一个命令,主shell仍然会等待它完成并关闭其 stdout 。为了避免等待这个过程,您需要将其输出重定向出管道。

echo "$( cat file1; sleep 3 >/dev/null & cat file2 )"

1
我的唯一限制是我不能编辑子shell中的函数调用。即使我可以从子shell中删除$,我也不会这样做,因为该函数产生需要被捕获的输出。 - Nelson
2
如果需要捕获输出,你必须等待其完成。否则主命令将在没有输出的情况下开始执行。 - Barmar
2
$(...)将运行带有连接到其stdout的管道的子命令,并等待管道上的EOF。这基本上意味着它必须等待命令完成,即使它在后台运行。那么将其放入后台的意义是什么? - Barmar
1
func() { some_stuff; sleep 3 &; more_stuff; };$(func)大致上是我所拥有的设置。我需要在func` 中执行其他代码并产生输出,这些输出将被捕获,但我也需要在“bg”中运行 sleep。看起来这在 bash 中不可能,这就是为什么我使用 c++ 解决方案的原因。 - Nelson
2
如果你不想等待它,你还需要重定向它的输出:git ... >/dev/null & - Barmar
显示剩余6条评论

2

我希望我理解得对。如果我错了,请纠正我——您想让主线程能够在子线程结束之前死亡吗? 如果是这种情况,您可以在线程上使用detach方法。


main()函数的前三行替换为thread::detach(); - Nelson
thread t(somefunction, somearguments); t.detach(); this_thread::sleep_for(chrono::milliseconds(3000)); - Coral Kashri
可以了,谢谢!虽然从bash转到c++不是最理想的选择,但我认为这是我能得到的最好的结果。 - Nelson
不客气,很高兴能帮上忙 :) 顺便说一句,你可能会在这里找到更有用的信息:https://superuser.com/questions/178587/how-do-i-detach-a-process-from-terminal-entirely - Coral Kashri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接