Detach your shell

You need to close your terminal but your shell isn't running inside tmux or screen. You want to save your session. What can you do?

| Enter Detach and Reptyr.

Reptyr

Reptyr is a utility for taking an existing running program and attaching it to a new terminal. Read about it here and here.

Download and build

$ git clone https://github.com/nelhage/reptyr
$ cd reptyr
$ make

reptyr depends on the ptrace(2) system call to attach to the remote program. This requires the ptrace scope (kernel.yama.ptrace_scope) which is likely to be disabled by default. You can check this:

$ cat /proc/sys/kernel/yama/ptrace_scope 
cat: /proc/sys/kernel/yama/ptrace_scope: No such file or directory

or by

$ sysctl kernel.yama.ptrace_scope

a "No such file or directory" or non-zero value means that it's disabled. root can enable it temporarily by doing

# echo 0 > /proc/sys/kernel/yama/ptrace_scope 

However, that enables it globally. A better, and persistent, way is to give the reptyr binary the CAP_SYS_PTRACE capability:

$ sudo setcap cap_sys_ptrace=eip /usr/bin/reptyr

There is an Arch Linux Package. It doesn't enable the ptrace scope because it's a potential security risk. Caveat emptor.

$ sudo setcap cap_sys_ptrace=eip /usr/bin/reptyr
Usage

Open a new terminal, identify the PID of the process to move into it and then

$ reptyr 1234

will move the process with PID `1234'.

A more refined example moves an existing foreground process into screen:

  • If it's a foreground process, background it.
  • Disown it (disown myapp), or whatever, so it isn't sent a SIGHUP when the shell closes, as receiving such a signal can cause it to terminate.
  • Launch screen or tmux and
  • Bring the process into it reptyr $(pgrep myapp).

Some alternatives include retty, neercs and injcode.

Detach

Detach is a wrapper around reptyr and tmux, screen or dtach. It takes a list if PID values and moves them into a session. If multiple PIDs are given then each one will be placed in its own window with the current (or specified) window being used for the first.

!dtach is a lightweight tool for detaching processes like tmux and screen but without their other features line sessions and windows. It's described in the next section.

It will use the TTY Stealing mode of reptyr if given a -T argument. In this mode the given PID's controlling terminal is moved as a whole. Usage is restricted to a single PID in this mode to keep things simple.

Detach has limitations:

  • It doesn't like it when there are multiple windows with the same name.
  • It doesn't know whether the target window has a shell prompt waiting to receive a reptyr command.
  • It can't tell if the reptyr was successful
  • and, most of all, it is a work-in-progress and should be used with caution!

Tests

Create some test files, open them in vi and background them:

$ for i in a b c d; do echo $i > /tmp/$i; vi /tmp/$i & done; jobs -l

Open a new tmux session:

$ tmux new-session -d -s test-detacher -n "test-window"

Move the vi sessions into it:

$ ./detach -s test-detacher -w test-window %{1..4}

Attach to tmux and confirm it has four vi sessions, each in its own window.

$ tmux attach -t test-detacher

When happy, kill the session

  • (from within) C-b (or whatever) then : kill-session
  • (from outside) tmux kill-session -t test-detacher

Then try again without -w and again without defining a session, e.g:

$ ./detach %{1..4}

which should create a new tmux session (e.g. detach_14887_session). Try also pane-split: horizontal (-S h) and vertical (-S v). And try TTY Stealing ('-T'). FInally try the detaching the current terminal:

$ ./detachls

Try similarly with screen.

  • screen -dmS test-detacher
  • screen -r -S <session>
  • screen -X -S <session> kill

And with dtach. Of course, the -S option has no effect.

Detach can be downloaded here. It's a work-in-progress and should be used with caution and at your own risk.

Dtach

Dtach is, in its own words,

A program that emulates the detach feature of screen

It's a lightwight alternative to a terminal multiplexer when all that you want to do is detach a process such as your current shell. You can start a dtach-able shell:

$ dtach -c /tmp/socket -z bash

A dtach session is identified by the socket file name given when creating it. The example /tmp/socket can be any valid writable path. The -z argument is optional; it lets bash, rather than dtach, respond to Ctrl+Z interrupts. It's options are documented on its man page.

To use dtach with reptyrto detach an existing process:

$ dtach -c /tmp/socket reptyr <pid>

It's handy to know about, but dtach has limitations; mainly it's a single session and it doesn't support inject text (like you can tmux send-key or screen -X stuff).

Update since writing about dtach and since writing a patch to add text injection support, I discovered another fork made in 2008 that has the original author's commit history going back to the initial revision in Septermber 2001. There is also a pull request made in May 2011 that provides a similar enhancement although, in my opinion, it is less pure in that it interprets the input string to apply escapes like \n and makes it a larger patch than mine. The pull request has never been taken up and the repository has had no activity since 2010 but there are several forks of it, the most recent activity being in 2014.

Also discovered is abduco which is, in its own words "very similar to dtach but is a completely independent implementation which is actively maintained, contains no legacy code, provides a few additional features, has a cleaner, more robust implementation and is distributed under the ISC license". There is an assertion by Ned Crigler, the original author of dtach, that abduco violates the copyright of dtach and, despite claiming to the contrary, is a derivative work of the dtach source code. I have not tried abduco. I have emailed my patch to Ned.

Updated Upstream: Ned has taken my patch and implemented a push mode that injects text supplied on standard input. He has published his dtach repository on GitHub and I have published a dtach-git package to the Arch Linux AUR.