1

I am using tmux 2.3 and want to define a command to send the paste-buffer to system clipboard. I have tried using the command below and every variant I can think of, but when I try to run it, I get a message saying it returns with exit code 1. When the run the command in sh it works fine and when I remove the xclip part it doesn't throw an error. How can I debug what is causing the error? I believe I have the correct command.

bind-key b run-shell "tmux show-buffer | xclip -sel clip -i > /dev/null"

1 Answers1

-1

note: the original question referred to tmux version 2.3, and I confirmed all of this works with both that version, and 3.2a

For me, this has usually been caused by the tmux session starting without the DISPLAY environment variable set, meaning xclip doesn't know how to communicate with the X Server. This AskUbuntu answer is more focused on SSH, but it includes a helpful paragraph:

To check whether X11 forwarding is enabled, look at the value of the DISPLAY environment variable: echo $DISPLAY. You should see a value like localhost:10 [...]. Note that if DISPLAY isn't set, it's no use setting it manually [...]

This is what it looks like in my local, non-SSH tmux session:

$ echo "${DISPLAY:?}"
:0

If you get something like the following, it means the DISPLAY variable isn't set:

$ echo "${DISPLAY:?}"
sh: 1: DISPLAY: parameter null or not set

It's better to figure out how to launch the tmux session inside the X Server session, but if you can launch a terminal inside the X Server session, it could be useful to find out what the DISPLAY variable is, and temporarily set it in the tmux session, to see if it works:

export DISPLAY=':0'

The Ubuntu Community Wiki has a brief and exhaustive introduction to shell variables (it mentions bash, but most of the info is applicable to most shells, except csh, tcsh, and fish, which are not POSIX_compliant); it describes DISPLAY near the end. Note that the export VARIABLE_NAME=value syntax is part of the POSIX shell programming language, and is very counter intuitive, even for those with experience in other languages. This Stack Exchange question has some more explanations of how to set environment variables.

You can usually start any command-line program inside an X Server session by starting a terminal application, and then running the command-line program using the shell in the terminal.

On GNOME this would look like:

  1. Login to your account
  2. Start Terminal
  3. Run tmux new-session as a command in Terminal (sometimes it connects to an already-running session anyways)

Once started, tmux will launch a shell with the DISPLAY environment variable set, and xclip should work:

$ xclip -verbose -out
Connecting to X server.
Using UTF8_STRING.

You may see other things, and if your clipboard already contains content, it will be echoed to the terminal. Try copying, highlighting, or selecting some text before running this.

If instead it shows:

xclip: command not found

This means that xclip isn't installed, or can't be found.

If xclip is working, then you can try to set the command as a tmux key binding (running this will probably only work when already inside a tmux session):

tmux bind-key -T prefix b run-shell "tmux show-buffer | xclip -se c -i > /dev/null"

running tmux list-keys | less shows the default key bindings, and the syntax for setting them in a configuration file

I explicitly added the keybinding to the prefix table. Commands (or keyboard shortcuts) in tmux's prefix table are run by first pressing a leading key sequence, which is Ctrl+b by default, or C-b in tmux's syntax. Pressing Ctrl+b then b (C-b b) should run the command. I'll use prefix to indicate that the prefix key combination should be pressed.

And we do get an error. tmux opens copy-mode with the content 'tmux show-buffer | xclip -se c -i > /dev/null' returned 1.

If the command run by run-shell prints any output to stdout, tmux opens copy-mode in the current pane, showing that output. If the shell command fails, it also displays a line stating the return or exit code. By default, prefix then q will exit copy-mode.

Many programs print errors to stderr instead of stdout, including tmux's show-buffer, so the error information is lost. To capture it, we can leave off the shell pipe, and change the shell redirection:

$ tmux show-buffer
no buffers

$ echo $? # prints 1 if the previous command failed 1

$ tmux run-shell "tmux show-buffer" 'tmux show-buffer' returned 1

$ tmux run-shell "tmux show-buffer 2>&1" no buffers 'tmux show-buffer 2>&1' returned 1

This error message is returned because, when tmux starts, by default there are no buffers.

If there are any buffers, the following command will show those buffers and their contents (by default, it's bound to prefix then =):

tmux choose-buffer

If there are no buffers, this command returns immediately with no output. If there are any buffers, choose-buffer presents a list containing all buffers, ordered by the last time they were used. Pressing and will scroll through the list, pressing Enter will paste the contents of the selected buffer to the current pane, and q will exit.

To create a buffer, used the set-buffer command:

$ tmux set-buffer "test content"
$ tmux save-buffer - && echo
test content

note: the && echo is needed because the content of the buffer does not end in a new-line

With at least one buffer, the show-buffer command opens copy-mode with the contents of the most recently set buffer.

Note as in the above shell session that the save-buffer command will print the contents of the most recently set buffer to a file, and if - is given as the filename, then it will print to stdout.

The original configuration should probably be*:

bind-key b run-shell "tmux save-buffer - | xclip -sel clip -i"

*I'm guessing that you're trying to copy something from tmux to the system clipboard.

Typically, text in tmux is selected by entering copy-mode first. By default, this is bound to prefix then [. With the default configuration, tmux uses Emacs-style keybindings in copy-mode. In tmux version 2.3, these keybindings can be shown with tmux list-keys -temacs-copy. In versions greater than 2.3, the list-keys command shows the keybindings in all tables by default.

note: vi-style keybindings can be used by replacing emacs-copy with vi-copy, or copy-mode-vi instead of copy-mode, in all commands and configurations

The selected text can be copied, both to the system clipboard and a tmux buffer. In tmux version 2.3, this is possible with something like:

bind-key -temacs-copy M-w copy-pipe "xclip -selection clipboard -in"

This would override the default behaviour of Alt+w in copy-mode to pipe the selected text to xclip, in addition to copying the selected text into a tmux buffer.

In versions greater than 2.3, the equivalent configuration would be:

bind-key -T copy-mode M-w send-keys -X copy-pipe-and-cancel "xclip -selection clipboard -in"

In both versions, the following would replace the default behaviour of prefix then ] with creating a tmux buffer with the contents of the X server clipboard, and then pasting the most recent buffer:

bind-key -T prefix ']' run-shell 'tmux set-buffer "$(xclip -selection clipboard -out)"' \; paste-buffer

Note that xclip can behave strangely in some circumstances when used like this.

Version 2.3 was released in 2016, so most package repositories should have a newer version.

Either way, I would recommend using tmux-yank, as it manages the task of copying from tmux very well.


As to debugging what is causing errors in tmux configurations, in general, there are a few things we can do to make that easier:

  • Run the commands from the terminal inside a tmux session (if possible)
  • Create a temporary configuration file
  • Show messages for longer

Run the commands from the terminal inside a tmux session (if possible)

Most commands that can be put in a configuration file, can also be run from inside a tmux session, from a command line, by prefixing them with tmux. Most shells will interpret certain characters like [ ] ; & " ' specially, so when running tmux commands, take care to quote those characters so that they are passed to tmux. All of the commands given above will work when prefixed with tmux, without modification, as well as in a configuration file.

Running the commands like this may not be possible, like when in copy-mode and the shell session isn't available.

When it is possible, this can help diagnose what exactly is happening with each part of a command.

Sometimes, the command can be run from tmux's command prompt (by default prefix then :). The command is entered just as in the configuration file, and pressing Enter runs it.

So for instance, in copy-mode, pressing prefix then : changes the status line to yellow with the content :, followed by the cursor. Typing a command like display-message test and then pressing Enter will set the content of the status line to test. To instead exit, press the terminal's interrupt key combination (default in most terminals is Ctrl+c; stty -a may show something like intr = ^C).

note: see the section "Show messages for longer" to increase how long these messages are shown in the status line

note: tmux version 2.4 and above allow running copy-mode commands from the command prompt, like send-keys -X begin-selection. I do not know how to do this in version earlier than 2.4.

Create a temporary configuration file

To help with debugging, we can add the potential configuration changes in a file called tmux_debug.conf:

# -q: do not return an error if the file doesn't exist
source-file -q /etc/tmux.conf
source-file -q ~/.tmux.conf

add any experimental configuration below here

and run tmux with:

tmux -f ./tmux_debug.conf

When tmux is started, by default it reads from two configuration files: /etc/tmux.conf and ~/.tmux.conf. The -f option instructs it to ignore those, and load a custom file. Since we may rely on configuration in those two, we source them if they exist. This will allow us to keep our current configuration without making permanent changes to it.

We can also add a keybinding for quick reloading of the temporary configuration file:

bind-key -T prefix C-r source-file ./tmux_debug.conf \; display-message "sourced configuration"

This will set the key sequence prefix then Ctrl+r to make tmux reload the tmux_debug.conf file in the directory in which tmux was started, and then show the text sourced configuration in tmux's status line.

Show messages for longer

The previous command displays a message in the status line. By default, tmux only shows messages in the status line for 750ms, which is a source of frustration.

In the configuration file, adding the following line will cause the text to be displayed until a key is pressed:

set -g display-time 0

note: the key press is sent to whatever is running in the pane or window that just had focus