r/tmux 12d ago

Tip Copy and Paste to Linux from Mac thru SSH

In case anyone runs into similar issues, I used the below .tmux.config to allow copying and pasting from a TMUX session running on Linux, which I SSH'd to from Mac. This is with mouse selection, and Cmd-c to copy. Automatic copy of whatever is selected doesn't work for me. Of course, if someone has a better set up, let me know.

# ~/.tmux.conf

set -g mouse off

set -g set-clipboard on

7 Upvotes

3 comments sorted by

1

u/yoshiatsu 10d ago

I use this:

#!/usr/bin/env bash

# Universal Cross-Machine Clipboard Sync

PATH="$HOME/bin:/usr/local/bin:/usr/bin:/bin:$PATH"

# 1. Capture Input once (File or Stdin)
if [ -n "$1" ]; then
    if [ -f "$1" ]; then
        INPUT_DATA=$(cat "$1")
    else
        echo "$0: file not found: $1" >&2
        exit 1
    fi
else
    INPUT_DATA=$(cat -)
fi

#echo "Length: ${#INPUT_DATA}"
#echo "Data: |$INPUT_DATA|"

# Exit early if input is essentially empty; one char is a stray click,
# not a copy.
[[ ${#INPUT_DATA} -lt 2 ]] && exit 0

# CIRCUIT BREAKER: If this variable is set, someone else called us.
# Stop the chain here and don't go recursive.
if [[ "$CLIP_INTERNAL" == "true" ]]; then
    exit 0
fi

# ROOT RE-EXEC
if [[ "$EUID" -eq 0 ]]; then
    exec sudo -u yoshiatsu -- "$0" "$@"
fi

export CLIP_INTERNAL="true"

function copy_locally() {
    local data="$1"

    # Always keep a copy on disk.  ~/.clipboard_buffer may be a symlink
    # into gdrive so that other machines can see it too.
    echo -n "$data" >~/.clipboard_buffer

    if [ "$(uname)" = "Darwin" ]; then
        echo -n "$data" | pbcopy
    elif [ "$(uname)" = "FreeBSD" ]; then
        if command -v xclip >/dev/null 2>&1; then
            echo -n "$data" | xclip -in -selection clipboard >/dev/null 2>&1
        fi
    elif [ "$(uname)" = "Linux" ]; then
        if [ -n "$WAYLAND_DISPLAY" ]; then
            echo -n "$data" | wl-copy
        else
            echo -n "$data" | DISPLAY=:0 XAUTHORITY=~/.Xauthority xclip -selection clipboard >/dev/null 2>&1
        fi
    fi
}

# 3. Remote Push Logic
function push_remote() {
    local host="$1"
    local data="$2"
    local ip=$(${HOME}/bin/resolve.sh "$host")
    #echo "push_remote: host=$host ip=$ip data_len=${#data}" >>/tmp/clip.log
    [[ -z "$ip" ]] && {
        echo "push_remote: no IP for $host, bailing." 2>&1
        return
    }
    #echo "SENDING TO ${host} at ${ip}..."
    REMOTE_CMD="CLIP_INTERNAL=true DISPLAY=:0 XAUTHORITY=\$HOME/.Xauthority xclip -selection clipboard >/dev/null 2>&1"
    echo -n "$data" | command ssh -qx -o ConnectTimeout=1 -o BatchMode=yes -o "HostName=$ip" "${host}-fast" "nohup sh -c '$REMOTE_CMD' < /dev/stdin &"
    if [ $? -ne 0 ]; then
        echo "push_remote: ssh exit code $?" 2>&1
    fi
}

# --- MAIN ---
copy_locally "$INPUT_DATA" &

# Push to laptops too if we aren't them.
SHORT_NAME=$(hostname -s)
if [[ "$SHORT_NAME" != cheetah* ]]; then
    push_remote "cheetah.house" "$INPUT_DATA" &
fi
if [[ "$SHORT_NAME" != tabby* ]]; then
    push_remote "tabby.house" "$INPUT_DATA" &
fi

wait

With this .tmuxrc

...
# When selection ends in copy mode, grab the selected text and send it
# in a pipe to the command 'clip' which stuffs it into the local clipboard
# and also into the laptops' clipboards.
bind -n MouseDrag1Pane "select-pane \; copy-mode \; set mode-style 'bg=#{TMUX_ACTIVE_PANE_BORDER}' \; s\
end-keys -X begin-selection"
bind -T copy-mode MouseDrag1Pane "set mode-style 'bg=#{TMUX_ACTIVE_PANE_BORDER}' \; send-keys -X begin-\
selection"
bind -T copy-mode MouseDragEnd1Pane "send-keys -X copy-pipe-and-cancel /home/yoshiatsu/bin/clip"
...

1

u/liberforce 8d ago

I only discovered a couple of weeks ago that with Term, you need to use Fn + mouse selection to be able to copy with Cmd + C.

1

u/greenspywork 6d ago

Giving iterm2 a try and already working better after enabling clipboard access.