11

I ssh into my VPS and run tmux. I can copy/paste from the remote to local, and local to remote - using the mouse and shift.

But I don't know how to copy large quantities of text.

If I were working locally, I could do this: cat somefile.txt | xsel -b or cat somefile | xclip -selection clipboard to copy into the clipboard. (I can't do that of course as the remote server doesn't run x, and even so the clipboard would not match the one used in tmux.)

So, how do I copy text in the tmux session, and for it to be duplicated over the wire to my local system's clipboard?

UPDATE:
Actually, this is applicable even without tmux - how to copy-paste large buffers between a remote and local shell.

lonix
  • 1,723
  • Same question here. On ubuntu using ssh to login to raspberry pi, and there running tmux, I'd like to be able to paste locally the selection that I put in the tmux buffer. Remarkable is that when I do the same on my chromebook linux terminal, the buffer is copied to the local clipboard. Really so! When I do the tmux copy mode on the remote machine and hit Enter, the terminal blinks the "copied" icon in the middle and I can paste the selected text locally! It's like magic, but I have no clue how to do the same on my ubuntu machine :( – vicmortelmans Feb 03 '21 at 21:51

3 Answers3

4

To have bidirectional clipboard (more here):

  1. Run ssh with -X to enable X11 forwarding.

  2. Install xsel (manipulate the X selection).

    sudo apt install xsel
    

That's it. Now, to test remote → local run on the remote host:

date +%Y-%m-%d_%T | xsel -b  # Or tee >(xsel -b) to send output also to stdout

On local host:

echo "Time on server is $(xsel -b)"

time will show how long it took the command to copy the text to the clipboard.

Notes

  • You can also use primary buffer instead:

    Selection options

    -p, --primary: operate on the PRIMARY selection (default).
    -b, --clipboard: operate on the CLIPBOARD selection.

  • tmux buffer stack might be enough on some cases.

  • -X Might need xauth on server.

  • xsel depends on libx11-6 and libc6 (apt depends xsel).

  • If you get xsel: Can't open display: (null) check this answer.

Pablo A
  • 2,712
  • Thank you. Strangely though this doesn't work for me. The command on the remote never returns (even without time), and the local doesn't reflect it. All dependencies installed. Maybe it's "just me". I'll try again later on another machine. Thanks once again! – lonix Oct 14 '21 at 07:42
  • echo foo | xsel -b on the server return any output? Try with ssh -Y, or with ssh -vvv to debug what's going on. You are using Wayland? time only returns how long the process took to run. – Pablo A Oct 14 '21 at 19:08
  • No wayland, I'm using ubuntu based server. Problem is maybe x11 forwarding which isn't setup properly as I've never needed it... I'll look into it again later. I upvoted as this if a good solution for those with x11 set up. There must be other options too, I hope that would work for me. – lonix Oct 15 '21 at 02:50
  • I'm also using an ubuntu server (20.4). I didn't do any further tweaks. Maybe you need some packages installed on server, like x11-common. If you provide more info, like the output of echo foo | xsel -b while connecting with ssh -vvv -Y maybe we could help. – Pablo A Oct 15 '21 at 20:26
1

In addition to Pablo's excellent answer above, if you are doing esoteric DISPLAY stuff, e.g. X11 forwarding for clipboard but using local display for OpenGL / CUDA machine learning stuff, then you may want to redirect your displays.

If you siphon an X11-forwarded display off into a separate env var, then you can have the "best" of both worlds.

It can look something like this:

# Bash function.
personal-ssh-session() {  # Call manually
    if [[ ! -v _SSH_DISPLAY && -v DISPLAY ]]; then
        export _SSH_DISPLAY=${DISPLAY}
        echo "Using redirect _SSH_DISPLAY=${_SSH_DISPLAY}"
    fi
    export DISPLAY=:1
}

Bash script, tmux-copy.sh

#!/bin/bash set -e if [[ -n "${_SSH_DISPLAY}" ]]; then export DISPLAY=${_SSH_DISPLAY} fi mkdir -p ~/tmp tee ~/tmp/tmux-clipboard.txt | xclip -in -selection clipboard

tmux bind command - be sure ${_DOTFILES} is set, or use something else

bind -T copy-mode-vi Enter send-keys -X copy-pipe
'${_DOTFILES}/tmux-copy.sh'

Example from https://github.com/eacousineau/dotfiles_template

  • Run inside X11-forward SSH session: bash_aliases func
    • This will set DISPLAY to use local gfx card vs. X11 forwarding (most likely software rendering)
  • Add script to handle redirect for clipboard; this also dumps current stuff in ~/tmp/tmux-clipboard.txt, just in case: bash script
  • Tell tmux to use this script: tmux bind command
0

The general correct way to handle this (which works through tunneled SSH as well, e.g. host -ssh-> server A -ssh-> server B) is with OSC52 xterm escape sequence. What happens is the app (in this case tmux or, say, neovim, with the osc52 plugin) will emit a OSC52 sequence copy buffer, if your terminal advertises it, and then your terminal will automatically assign that to the clipboard on your local host. Note in this case the escape sequence and its payload will travel transparently through the SSH session. the escape sequence takes care of preventing the conntent of the buffer however long it is from cluttering or corrupting your terminal output.

See tmux's manpage doc:

set-clipboard [on | external | off]

Attempt to set the terminal clipboard content using the xterm(1) escape sequence, if there is an Ms entry in the terminfo(5) description (see the TERMINFO EXTENSIONS section).

If set to on, tmux will both accept the escape sequence to create a buffer and attempt to set the terminal clipboard. If set to external, tmux will attempt to set the terminal clipboard but ignore attempts by applications to set tmux buffers. If off, tmux will neither accept the clipboard escape sequence nor attempt to set the clipboard.

Note that this feature needs to be enabled in xterm(1) by setting the resource:

disallowedWindowOps: 20,21,SetXprop

Or changing this property from the xterm(1) interactive menu when required.

Steven Lu
  • 2,282