How to cleanly launch a GUI app via the Terminal?

Suppose gedit is the program you want to run detached (aka. "disowned", "disentangled", "decoupled"). There are different ways depending on what you want to do exactly:

Program already running

Disown:

disown -h is the way to go if you want to do that with an already running program (i.e. if you forgot to nohup it). You first have to stop it using Ctrl+Z. Then you can put in in the background using bg [jobId] (e.g. bg 1). You get a list of running jobs with their jobId using jobs. After that you can decouple it from terminal using disown -h %[jobId]. Example terminal session:

$ gedit 
^Z
[1]+  Stopped                 gedit
$ jobs
[1]+  Stopped                 gedit
$ bg 1
[1]+ gedit &
$ disown -h %1
$ exit

Program not started yet

nohup

nohup is not always present on all machines. If you know you want to decouple beforehand you would use:

nohup gedit &

Maybe you will want to redirect the shell output as well and your program a pseudo input source, so: nohup ./myprogram > foo.out 2> bar.err < /dev/null &. You would want to redirect the output to either not be annoyed by it or to use it later. The null-input can help to prevent hickups in ssh an such.

Subshell:

You can achieve a similar effect by

$ (geany >/dev/null 2>&1 &)

The brackets open a new subshell to run gedit in. The >/dev/null 2>&1 redirects the shell output to nowhere (suppressing the output). And the & at the end puts the process in the background.

Terminal multiplexing

Also terminal multiplexing using screen or byobu. You basically run the program in a terminal of its own. I can really recommend byobu for other reasons too. Below is a list of boybu-shortcuts that might come in handy for your first steps:

Useful:

  • F2 Create a new window
  • F3 Move to the next window
  • F4 Move to the previous window
  • F6 Detach from the session and logout
  • Shift-F6 Detach from the session, but do not logout
  • F7 Enter scrollback/search mode
  • Ctrl-F5 Reconnect any SSH/GPG sockets or agents

Less useful:

  • Shift-F2 Split the screen horizontally
  • Ctrl-F2 Split the screen vertically
  • Shift-F3 Move focus to the next split
  • Shift-F4 Move focus to the previous split
  • Shift-F5 Collapse all splits
  • F5 Refresh all status notifications
  • F8 Rename the current window
  • F9 Launch the Byobu Configuration Menu
  • F12 GNU Screen's Escape Key
  • Alt-Pageup Scroll back through this window's history
  • Alt-Pagedown Scroll forward through this window's history
  • Ctrl-a-! Toggle all of Byobu's keybindings on or off

The 'at' daemon and others

at is a nice useful little tool to run a command at a scheduled time. It can be 'misused' to detach a command from the shell:

echo './myprogram myoption1 myoption2' | at now

Also you can look into setsid and start-stop-daemon, but the other methods should suffice.


To start an application and detach it from the launched terminal use &!.

firefox &!

The mysterious ampersand "&" suffix, seems to cause the terminal to put the process into the background... (but I'm not sure what happens there).

It does, and is often what you want. If you forget to use &, you can suspend the program with ctrl-z then place it in the background with the bg command — and continue to use that shell.

The process' stdin, stdout, and stderr are still connected to the terminal; you can redirect those from/to /dev/null or any other file (e.g. save an output log somewhere), as desired:

some-program </dev/null &>/dev/null &
# &>file is bash for 1>file 2>&1

You can see the process in jobs, bring it back to the foreground (fg command), and send it signals (kill command).

Some graphical programs will detach from the terminal; if that's the case, when you run the command "normally" you'll notice it starts the graphical program and "exits".


Here's a short script, you can place it in ~/bin, which I named runbg:

#!/bin/bash
[ $# -eq 0 ] && {  # $# is number of args
  echo "$(basename $0): missing command" >&2
  exit 1
}
prog="$(which "$1")"  # see below
[ -z "$prog" ] && {
  echo "$(basename $0): unknown command: $1" >&2
  exit 1
}
shift  # remove $1, now $prog, from args
tty -s && exec </dev/null      # if stdin is a terminal, redirect from null
tty -s <&1 && exec >/dev/null  # if stdout is a terminal, redirect to null
tty -s <&2 && exec 2>&1        # stderr to stdout (which might not be null)
"$prog" "$@" &  # $@ is all args

I look up the program ($prog) before redirecting so errors in locating it can be reported. Run it as "runbg your-command args..."; you can still redirect stdout/err to a file if you need to save output somewhere.

Except for the redirections and error handling, this is equivalent to htorque's answer.