I've noticed that calling xdg-open from a subshell will reliably block until the launched process is closed. I suspect there may be a reason for this, but I'm not sure as to why. For example, launching Nautilus doesn't block when calling xdg-open directly from the command line:

xdg-open ~/dir ; echo foo              # doesn't block

but invoking xdg-open from a subshell will reliably block the terminal

var=$(xdg-open ~/dir ; echo foo)       # blocks

{ xdg-open ~/dir ; echo foo ; } | cat  # blocks.

My understanding is that xdg-open detaches the launched process from the shell session so that it's no longer a subprocess. I'd therefore expect this to be different to e.g. invoking sleep 1 & in a subshell for which it seems reasonable that the terminating subshell will block until all subprocess have completed, i.e.

var=$(sleep 1 & echo foo)      # also blocks, but understandable.

But if xdg-open is detaching the process, what's causing the subshell to wait?

In what may (?) be a partial answer, I've noticed that running

{ xdg-open <file> ; ps ; } | cat

shows that depending on program launched by <file>, those that block are also the ones that keep the tty as their controlling terminal. That begs the question why this happens, why this happens only in a subshell and ultimately what's a good way to a launch desktop process from the terminal that will fully and reliably detach from it?

Edit: fix syntax on bash.

  • Which shell are you using? If bash, note that subshells are started with (...). – Eduardo Trápani Dec 12 '20 at 21:48
  • I'm using zsh, but I observe the same with bash. Note the use of {...} was to simplify the example - the output is piped to cat so my understanding is it is still invoked in a subshell. You get the same behavior in bash if you wrap in a function from which you pipe the output. – wardw Dec 12 '20 at 21:57
  • Ok, but, what is it you're trying to do? xdg-open will end up calling the appropriate application, so your results may vary, they may even depend on whether there's already an open window for that application or not... – Eduardo Trápani Dec 12 '20 at 22:01
  • I'm trying to launch a program via xdg-open from a subshell without blocking the shell that invokes xdg-open. When xdg-open is invoked outside of a subshell the shell doesn't block - I would like to do this reliably in both cases, and better understand why there's a difference. – wardw Dec 12 '20 at 22:15
  • An ampersand at the end of the command is not enough? xdg-open ... & – Eduardo Trápani Dec 12 '20 at 22:21

First of all, in your examples,

var=$(sleep 1 & ; echo foo)

should not work in bash, because & already serves as a line end.
(-bash: command substitution: line 1: syntax error near unexpected token `;')


var=$(sleep 1 & echo foo) # no ';' !!

(echo $var: foo)

In my understanding, a simple

xdg-open <something> & # optional: echo foo

should do the trick, either in a sub-shell or outside.

  • You're right - I checked in bash and the example fails. I was doing this in zsh which seems more forgiving, but your approach is portable and probably correct regardless. But I think the use of & here is a distraction, since running a command in the background (of the subshell) is still insufficient since I assume the parent process must still wait for the child (subshell) to fully complete before execution of the parent can progress. But xdg-open should fully detach the launched process and complete? Perhaps it's a just a quirk of xdg-open or something I'm not considering. – wardw Dec 13 '20 at 0:33
  • @wardw You can also try starting xdg-open without '&', then go back to the terminal, press Ctrl+Z and type bg X (Replace X with the number from the prompt, e.g. [X]+ Stopped xdc-open <something>). That should manually send it to background and finish detached from your active terminal. – Andre Wildberg Dec 13 '20 at 1:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.