3

I want to be able to bg a process inside a subshell as if it were not in a subshell.

$( sleep 3 & ) just ignores the ampersand.

I've tried:

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

but nothing changes.

Then I tried $( disown sleep 3 & ) which returned

disown: can't manipulate jobs in subshell

which led me to try $( set -m; disown sleep 3 & ) but I got the same output.

I even tried creating a c++ program that would daemonize itself:

#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;
}

But after running it, realized that because I am forking instead of separate_from_parent_and_let_parent_dieing the subshell will still wait for the process to end.

To step out of my MCVE, a function is being called from a subshell, and in that function, I need to pull data from a server and it needs to be run in the bg. My only constraint is that I can't edit the function call in the subshell.

Is there any way to not fork but separate from the parent process in a c++ program so that it can die without consequence or force a command to separate from a subshell in bash?

Preferably the latter.

Nelson
  • 922
  • 1
  • 9
  • 23
  • 2
    What are you really trying to do? `$(...)` is for running a command and putting its output into the current shell command. If you run the command in the background, how can you capture its output? – Barmar May 30 '18 at 22:23

2 Answers2

5

The $(...) command substitution mechanism waits for EOF on the pipe that the subshell's stdout is connected to. So even if you background a command in the subshell, the main shell will still wait for it to finish and close its stdout. To avoid waiting for this, you need to redirect its output away from the pipe.

echo "$( cat file1; sleep 3 >/dev/null & cat file2 )"
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    "My only constraint is that I can't edit the function call in the subshell." Even if I could remove the `$` from the subshell, I wouldn't because the function produces output that needs to be captured. – Nelson May 30 '18 at 22:29
  • 2
    If it needs to be captured, you have to wait for it to finish. Otherwise the main command will just start executing without the output. – Barmar May 30 '18 at 22:31
  • 2
    `$(...)` will run the subcommand with a pipe connected to its `stdout`, and it will wait for EOF on the pipe. That basically means it has to wait for the command to finish, even though it's in the background. So what's the point of putting it in the background? – Barmar May 30 '18 at 22:34
  • 1
    `func() { some_stuff; sleep 3 &; more_stuff; };`$(func)` Is roughly the setup I have. I need the other code in `func` to execute and produce output that will be captured, but I also need to run sleep in the "bg". It doesn't look like this is possible in bash which is why I am using the c++ solution. – Nelson May 30 '18 at 22:38
  • Get rid of the `;` after `&`. – Barmar May 30 '18 at 22:39
  • 1
    `func() { some_stuff; sleep 3 & more_stuff; }` – Barmar May 30 '18 at 22:40
  • 1
    `&` is a command separator just like `;`. Putting `;` after it creates an empty command, and that's not allowed. – Barmar May 30 '18 at 22:41
  • 1
    I still don't understand the point of that. It just means that the `$(func)` will be delayed 3 seconds after `some_stuff` finishes, even if `more_stuff` takes less time. – Barmar May 30 '18 at 22:42
  • 1
    `sleep 3 &` is just a placeholder. It represents a git command in my script that pulls data from a repo. The latency from that download is causing issues, which is why I'm trying to run it in the background. – Nelson May 30 '18 at 22:45
  • 2
    If you don't want to wait for it, you'll also need to redirect its output: `git ... >/dev/null &` – Barmar May 30 '18 at 22:56
  • Absolutely dumbfounded. I can't believe it was that simple. – Nelson May 31 '18 at 00:21
2

I hope I've got you right. Fix me if I'm wrong- you want that your main thread will ba able to die before the sub-threads ends? I f this is the situation you can use detach method on the thread.

Coral Kashri
  • 3,436
  • 2
  • 10
  • 22
  • as in replace the first 3 lines of `main()` with `thread::detach();` ? – Nelson May 30 '18 at 22:12
  • ``thread t(somefunction, somearguments); t.detach(); this_thread::sleep_for(chrono::milliseconds(3000));`` – Coral Kashri May 30 '18 at 22:17
  • It works, thank you!! Moving from bash to c++ is not ideal but I think it's the best I'm going to get. – Nelson May 30 '18 at 22:30
  • You're welcome, glad to help :) BTW, you might find something more helpful about the bush here: https://superuser.com/questions/178587/how-do-i-detach-a-process-from-terminal-entirely – Coral Kashri May 30 '18 at 22:48