9

My method for disowning the foreground process takes too much effort.

Suppose I have a process in zsh's foreground. I want to disown it, so I can close the shell without the process being sent a SIGHUP.

At the moment, I start with Ctrl+z to background and pause the process, then

$ disown
disown: warning: job is suspended, use `kill -CONT -32240' to resume
$ kill -CONT -32240
$

then I can close the terminal.

How can I automate that? Ideally, I'd like to be able to press Ctrl+j or something to immediately disown the running process. Or second best, I'd want to be able to run a single command to both disown and SIGCONT the process once it's suspended.

2
  • 4
    It is easier to bg+disown instead of kill -CONT -1234.
    – jimmij
    Aug 15, 2015 at 22:11
  • I used to use alias dr='disown -r' in bash. bg and dr do the trick. Aug 16, 2015 at 14:37

3 Answers 3

14

Having a global keybind to disown the foreground process is impossible: Keystrokes are received by the foreground process, not by the shell. You need to first suspend it with Ctrl+z if you want to disown it.

However, turns out there's a zsh option to speed up disowning then continuing: With setopt AUTO_CONTINUE, disown will automatically also send SIGCONT.

So you can get it down to C-z disown.

0
13

When you press Ctrl+Z in a terminal, this causes the foreground process group to receive the signal SIGTSTP (assuming the terminal is in cooked mode and the default key bindings are in place). If the process hasn't set a signal handler for SIGTSTP, this causes the process to be suspended (and even if the process has set a signal handler, it usually only does a small amount of processing before suspending itself). When a process is killed, suspended or resumed, its parent is notified via a SIGCHLD signal; this is what causes the shell to display a new prompt and maybe a message like [1] + 1234 suspended foo. The information flow is
    key → suspension → shell
and not
    key → shell → suspension
so you can't configure a different reaction for Ctrl+Z.

You can set a trap for SIGCHLD, but the trap is not executed when the job is the current foreground job. For the most part, this means that the trap is executed only when a background job terminates, not when the foreground job terminates. But it also means that you can't react to the suspension of the foreground job.

You can indirectly react to changes in background jobs by setting a precmd hook that compares the job states with states saved from the previous precmd run. But I don't know what you could do with that: there can only be a single suspend key, so you need some extra information to know whether the process was meant to be paused, backgrounded or disowned.

I've set up zsh so that pressing Ctrl+Z at an empty prompt backgrounds the current job. This lets me press Ctrl+Z twice to put the foreground job into the background with only a short suspension.

fancy-ctrl-z () {
  if [[ $#BUFFER -eq 0 ]]; then
    bg
    zle redisplay
  else
    zle push-input
  fi
}
zle -N fancy-ctrl-z
bindkey '^Z' fancy-ctrl-z

You could make it call disown if you like. Or you could arrange for a third Ctrl+Z to call disown with the following untested modification.

fancy-ctrl-z () {
  if [[ $#BUFFER -eq 0 ]]; then
    if (($fancy_ctrl_z_already_bg)); then
      disown
    else
      bg
      fancy_ctrl_z_already_bg=1
    fi
    zle redisplay
  else
    zle push-input
  fi
}
zle -N fancy-ctrl-z
bindkey '^Z' fancy-ctrl-z
fancy_ctrl_z_precmd () {
  fancy_ctrl_z_already_bg=0
}
precmd_functions+=fancy_ctrl_z_precmd
4
  • Note that you don't need the full cooked mode for ^Z to work. isig is enough (even without icanon) Aug 17, 2015 at 14:35
  • So the SIGTSTP is sent by the terminal emulator? Is it possible to configure the emulator (any that you know) to change what it does for a ^Z? Like in the shortcut preference? May 1, 2017 at 4:58
  • @FranklinYu The terminal emulator sends SIGTSTP when you press Ctrl+Z while a program is running and the feature is activated in the terminal interface (stty +isig). You can change which character triggers this with the stty command (you can't set an arbitrary key, it has to be a single byte, not an escape sequence). While the shell is in the foreground, it changes the terminal settings to take over key presses so the effect of Ctrl+Z depends on the shell's key bindings. May 1, 2017 at 9:58
  • 1
    It's not the terminal emulator that sends the signal, it's the kernel (the tty driver, or tty line discipline that is attached to the serial or pty device). All the terminal device does is sending byte 26 when you press Ctrl+Z Aug 17, 2022 at 15:23
1

For the second best, pressing Ctrl+z then typing a combination of % and &|

$ %&|

will disown the process without needing to SIGCONT it.

From zshbuiltins(1):

SHELL BUILTIN COMMANDS
       …
       disown [ job ... ]
       job ... &|
       job ... &!

              … If one of the latter two forms is used, the jobs
              will  automatically  be  made running, independent of
              the setting of the AUTO_CONTINUE option.

and zshmisc(1):

JOBS
       …
       There are several ways to refer to jobs in the shell.
       A job can be referred to by the process ID of any
       process of the job or by one of the following:
       …
       %string
              The last job whose command line begins with string.
1
  • 1
    The main reason I added that description was to clarify what that % was, which for people not familiar with job specification would seem obscure. If you know % is the most recently suspended job (or most recently started in background), you're less surprised when %&! disowns the wrong job just because some job got suspended between the time you pressed C-Z and the time you ran disown or %&!. Aug 19, 2022 at 15:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .