Skip to content(if available)orjump to list(if available)

How to move a running process into a tmux session (2020)


I was curious how this worked so I did some reading which I found interesting. In short, this uses ptrace, which is the same Linux kernel mechanism used by debuggers, to attach to a running process and manipulate the open file descriptors (amongst other things) while it runs. So basically it attaches to the process, and changes stdin (fd 0) and stdout (fd 1) to point to your tmux session stdout and stdin.

Pretty cool use of ptrace.


This is pretty cool! I had done something similar to connect isolated processes on the fly last year. But never thought to do that with tmux as a target.


yes i didnt think theres a way to do this without hacks. unportable and fragile as expected.


It's a nice tool (reptyr), but not particularly convenient to use, requiring several steps to move the process to the background and remembering the PID etc. I do wish this was a more streamlined, standard feature of Unix/Linux shells. Something like a simple integrated "pushproc"/"popproc" command.


Seems not super hard to do. A shell function could do the bg, disown, and use the tmux remote API to start a new window and remotely execute reptyr in it.




"Do one thing and do it well."


Judging from the amount of infrastructure that’s been built around background text-mode processes, job control does half a thing and sucks at it. It’s still mandatory, so I wouldn’t blame people for wanting to streamline the process of disassociating from that half-baked builtin support and substituting it with a replacement mechanism.


The streamlined version is what "screen -d …" does, so it's some kind of standard feature, isnt it?. The only "drawback" I see is that you have to plan ahead to use screen.

When I start long running jobs, I try do start them that way, so I can check on them (and their output in a screen logfile) from anywhere:

screen -L -Logfile "batch-xyzzy-221005a" -S "xyzzy1" bash

Now I can just check the log with grep or less, or reattach to it if some action is needed.


I also use tmux beforehand, when I plan ahead. But I think this discussion is about those situations where you didn't plan ahead and still need to somehow keep a process running.


> Take away the ownership from the shell using disown

Interesting. So far, my only ever use of disown was to decouple GUI apps that I launched from the terminal. I do that automatically now, as it's annoying when you forget, close the terminal, and a bunch of apps go away.


Just for curiosity: what was the purpose of "disown"? If I recall correctly, it was used so the shell you used to launch the process didn't kill it using a "hang" signal or something like that. But I made a quick test and my shell doesn't seem to kill the background process launched from it, at least when I quit using ctrl + d.


Behaviour depends on your shell. With Bash, for instance:

> The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. [...] To prevent the shell from sending the SIGHUP signal to a particular job, it should be removed from the jobs table with the disown builtin (see Job Control Builtins) or marked to not receive SIGHUP using disown -h.

> If the huponexit shell option has been set with shopt (see The Shopt Builtin), Bash sends a SIGHUP to all jobs when an interactive login shell exits.


Thanks! I've been doing some tests with the huponexit option but it seems the tricky part was this: when an interactive login shell exits

I think I remember in Linux many years ago (more than 15, maybe) the behavior was present in shells spawned from your DE, but I may be wrong.


Use a terminal like kitty that does not close as long as some launched program is still connected to it.


How does this compare to using

    nohup <gui-app> &



As others said, wish this use case had been considered on Unix based OSs. I guess it's a very common issue many people have daily. I don't like to do it but some people have some bashrc or ssh config script to auto attach every session to a tmux session or even docker container.


This is standard practice for systems following STIGs. Bashrc is required to enforce that new sessions always get a tmux and stay in the tmux session.


On a multi user system this seems fraught. That’s probably why it didn’t happen sooner.


I tried this on Ubuntu 22.04.1 and got an error:

    $ reptyr 10330                                                                                                                                                
    Unable to attach to pid 10330: Operation not permitted 
    The kernel denied permission while attaching. If your uid matches
    the target's, check the value of /proc/sys/kernel/yama/ptrace_scope.
    For more information, see /etc/sysctl.d/10-ptrace.conf
I haven't (yet) looked into how to fix or work around this problem.


Either, as root:

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

or permanently by editing the file /etc/sysctl.d/10-ptrace.conf


What are the costs and / or downsides to enabling prace_scope?


> What are the risks in setting ptrace_scope to 0?

> - This restores the old behavior where one process can "trace" another process, even if there is no parent-child relationship.

> - In theory, a piece of malware can use this to harm you/your computer; e.g. it can attach to Firefox and log all of your URLs/passwords, etc. In practice this is extremely unlikely unless you blindly install binary debs from random sites, etc.

> - As far as debugging goes, the 0 settings is in fact required for gdb, strace, etc. to attach to non-children unless you run them with elevated privileges (sudo).


were you root?


No, I wasn't root.


> It’s rare, but sometimes it still happens that I forget to open a tmux or screen session when working with something that is supposed to be quickly done.

There are various ways to get ahead of this problem too if you ssh into a tmux session automatically. There are various ways to achieve this.

I didn't know about reptyr, it's very cool. There were times I wished this was possible, but whenever I searched for a solution I got "It's not possible". Oh well...


Yes! I have a shell function that automatically attaches to an existing tmux session or creates a new tmux session if none exists already, after logging into the remote system via SSH:

  ssht() {
      ssh -t $1 'tmux a || tmux'


Don't you find it painful having your tmux session rooted in your homedir (e.g. for all new windows)? I nearly always need to have it anchored some project working directory.


I have tmux anchored to ~ because I hated new shells inheriting random cwd states. Instead I have a function to cd to "bookmarks" with an easy way to add to it and completion.


I have the following in my ~/.tmux.conf so that whenever I split pane or create a new tmux window, it sets the current working directory of the new pane or window to the same directory in which I was before:

  # Open new pane or window with the current directory
  bind '"' split-window -c "#{pane_current_path}"
  bind % split-window -h -c "#{pane_current_path}"
  bind c new-window -c "#{pane_current_path}"
So although the tmux session is run in my home directory, I only need to change the current working directory to my project directory once and then when I create new panes and windows, they have the project directory as the current working directory.


I have an autossh + tmux setup. It's along the lines of

  autossh -M 0 -t remote "tmux new-session -A -D -s $RANDOM$RANDOM$RANDOM$RANDOM"
with appropriate ServerAliveInterval and ServerAliveCountMax settings. It works somewhat nicely with dodgy ssh conncetions too. I'm aware of mosh, but this one even outlives when I put the laptop to sleep. Also mosh doesn't allow X forwarding, and I enable that for sharing the clipboard (yes, I'm aware of the security implications). And if I want to leave something long-running, I can just close the window and reattach later.


Mosh should survive a laptop sleep no problem - if it doesn't, something is misconfigured. X forwarding is a dealbreaker though.


One problem of course is that you miss the output of the process from before you took over control. Perhaps shells could be extended to better support this way of using tmux/screen.

By the way another approach is of course to use VNC (e.g. some process started in an xterm at work you can access by opening your entire desktop at home.)


Doesn't really feel like the shell would be the right place to do this, as the shell really has no idea, in most cases, of the output history. The whole idea of the scrollback is in the terminal, so it'd probably be, ultimately, the terminal that is the source of this information.

kitty probably has some abilities to do this easily from the shell, as it has all sorts of abilities to interact programmatically with the scrollback history.


Good point.

How about starting tmux by default inside a terminal, rather than running the shell directly inside the terminal?

Of course, an ssh session would also need to start tmux.




No need to `bg` the process. The `reptyr` tool should set it to run once it's gotten ptrace control over it.


This sounds like something that mosh was built for.


Mosh helps of course by not killing the child process on timeout, but you'll miss all the console output without something like tmux


I feel embarrassed to call myself a tmux fan learning this has been around since at least 2011.


not denying value of the article, it's great, but kinda solved problem for me - for multiple years, 99% of cases the first command after ssh login to server is `tmux attach || tmux` for me. Almost never run anything not in tmux/screen.


I think you can just do `tmux new -A`. IIRC this is equivalent to `tmux attach || tmux`.


Could be, will note on that.

In practice I have it via bash alias `tma` , not long command as described. Until I can't bring my .bashrc to particular server of course - there long one, may try your suggestion though


The ability to attach a detached process to any terminal should be a coreutil.


It sort of is? bg / fg / jobs, anyway


Unrelated to the article, but my favourite tmux trick is joining an existing tmux session to use as a collaborative (terminal) environment over ssh.

Remote pair coding made fun again!


Very cool! I hope this becomes a standard feature of all common Unix OSes. Will have to look at what part of this is architecture specific so it can be properly abstracted.