tmux系统剪切板
by Alexey Samoshkin
通过阿列克谢·萨莫什金(Alexey Samoshkin)
This is the 4th part of my tmux in practice article series.
这是我的tmux实践文章系列的第4部分。
In the previous part of “tmux in practice” series we talked about things like scrollback buffer, copy mode, and slightly touched on the topic of copying text into tmux’s copy buffer.
在“ tmux实践”系列的上一部分中,我们讨论了诸如回滚缓冲区,复制模式之类的内容,并略微涉及了将文本复制到tmux的复制缓冲区中的主题。
Sooner or later you’ll realize that whatever you copy in tmux gets stored in tmux’s copy buffer only, but not shared with system clipboard. Copying and pasting are such common operations, that this limitation is itself enough to turn tmux into a useless brick, despite other goodies.
迟早您会意识到,在tmux中复制的内容只会存储在tmux的复制缓冲区中,而不会与系统剪贴板共享。 复制和粘贴是非常常见的操作,尽管有其他好处,但这种限制本身足以将tmux变成无用的积木。
In this post we’ll explore how to build a bridge between the tmux copy buffer and system clipboard, to store copied text on system clipboard, in a way that address both local and remote usage scenarios.
在本文中,我们将探讨如何在tmux复制缓冲区和系统剪贴板之间建立桥梁,以将复制的文本存储在系统剪贴板中,从而解决本地和远程使用场景。
We’ll discuss following techniques:
我们将讨论以下技术:
Linux only, share text with X selection using xclip
or xsel
commands
仅限于Linux,使用xclip
或xsel
命令与X选择共享文本
Techniques above address only local scenarios. To support remote scenarios there are 2 extra methods:
以上技术仅针对本地情况。 为了支持远程方案,有2种其他方法:
Use the ANSI OSC 52 escape sequence to talk to controlling/parent terminal to manage and store text on a clipboard of a local machine.
使用ANSI OSC 52转义序列与控制/父终端进行对话,以管理文本并将其存储在本地计算机的剪贴板上。
Setup a local network listener which pipes input to pbcopy
or xclip
or xsel
. Pipe copied selected text from remote machine to a listener on the local machine through SSH remote tunneling. This is rather involved, and I will devote a dedicated post to describe it.
设置一个本地网络侦听器,该侦听器将输入管道传输到pbcopy
或xclip
或xsel
。 通过SSH远程隧道将复制的选定文本从远程计算机传输到本地计算机上的侦听器。 这相当复杂,我将专门介绍它。
pbcopy
and pbpaste
commands allow you to interact and manipulate system clipboard from command line.
pbcopy
和pbpaste
命令允许您pbpaste
进行交互和操作系统剪贴板。
pbcopy
reads data from stdin
and stores it in the clipboard. pbpaste
does the opposite and puts copied text on stdout
.
pbcopy
从stdin
读取数据并将其存储在剪贴板中。 pbpaste
进行相反的操作,并将复制的文本放在stdout
。
The idea is to hook into various tmux commands, that manage to copy text while in copy mode.
这个想法是挂接到各种tmux命令中,这些命令在复制模式下可以复制文本。
Let’s list them:
让我们列出它们:
$ tmux -f /dev/null list-keys -T copy-mode-vi
bind-key -T copy-mode-vi Enter send-keys -X copy-selection-and-cancelbind-key -T copy-mode-vi C-j send-keys -X copy-selection-and-cancelbind-key -T copy-mode-vi D send-keys -X copy-end-of-linebind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-selection-and-cancelbind-key -T copy-mode-vi A send-keys -X append-selection-and-cancel
copy-selection-and-cancel
and copy-end-of-line
are special tmux commands which tmux understand when pane is in copy mode. There are two flavors of copy command: copy-selection
and copy-pipe
.
copy-selection-and-cancel
和copy-end-of-line
是特殊的tmux命令,当窗格处于复制模式时,tmux会理解这些命令。 复制命令有两种形式: copy-selection
和copy-pipe
。
Let’s rewrite Enter
keybinding with copy-pipe command:
让我们用copy-pipe命令重写Enter
键绑定:
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "pbcopy"
copy-pipe
command stores selected text in tmux buffer same to copy-selection
, plus pipes selected text to the given command pbcopy
. So we get text stored in two places: the tmux copy buffer and the system clipboard.
copy-pipe
命令将所选文本存储在与copy-selection
相同的tmux缓冲区中,另外pbcopy
所选文本通过管道传输到给定命令pbcopy
。 因此,我们将文本存储在两个位置:tmux复制缓冲区和系统剪贴板。
So far so good. However, on some versions of OSX, pbcopy
and pbpaste
fail to function properly when run under tmux.
到目前为止,一切都很好。 但是,在某些版本的OSX上,在tmux下运行时, pbcopy
和pbpaste
无法正常运行。
Read more details from Chris Johnsen on why it happens:
从Chris Johnsen阅读更多有关发生原因的详细信息 :
tmux uses the daemon(3) library function when starting its server process. In Mac OS X 10.5, Apple changed daemon(3) to move the resulting process from its original bootstrap namespace to the root bootstrap namespace. This means that the tmux server, and its children, will automatically and uncontrollably lose access to what would have been their original bootstrap namespace (i.e. the one that has access to the pasteboard service).
tmux在启动其服务器进程时使用daemon(3)库函数。 在Mac OS X 10.5中,Apple更改了daemon(3)将结果进程从其原始引导程序名称空间移至根引导程序名称空间。 这意味着tmux服务器及其子级将自动失去控制,无法访问其原始引导程序名称空间(即有权访问粘贴板服务的名称空间)。
A common solution is to use reattach-to-user-namespace wrapper. This allows us to launch a process and have that process be attached to the per-user bootstrap namespace, which makes the program behave as we are expecting. You need to change keybinding properly:
常见的解决方案是使用重新附加到用户命名空间包装器。 这使我们可以启动一个进程,并将该进程附加到每个用户的引导程序名称空间,这使程序的行为符合我们的预期。 您需要正确更改键盘绑定:
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel “reattach-to-user-namespace pbcopy”
Plus, you would need to tell tmux to run your shell (bash, zsh, …) inside a wrapper, by setting default-command
option:
另外,您需要通过设置default-command
选项来告诉tmux在包装器中运行您的shell(bash,zsh等):
if -b "command -v reattach-to-user-namespace > /dev/null 2>&1" \ "run 'tmux set -g default-command \"exec $(tmux show -gv default-shell) 2>/dev/null & reattach-to-user-namespace -l $(tmux show -gv default-shell)\"'"
Note: some OSX versions works fine even without this hack (OSX 10.11.5 El Capitan), whereas OSX Sierra users report this hack is still needed.
注意 :即使没有这种破解,某些OSX版本也可以正常工作(OSX 10.11.5 El Capitan),而OSX Sierra用户报告仍然需要这种破解 。
We can make use of xclip
or xsel
commands on Linux to store text in the clipboard, same as pbcopy
on OSX. On Linux, there are several kinds of clipboard selections maintained by X server: primary, secondary and clipboard. We only concern with primary and clipboard. Secondary was intended as an alternate to primary.
我们可以在Linux上使用xclip
或xsel
命令将文本存储在剪贴板中,就像OSX上的pbcopy
一样。 在Linux上,X服务器维护几种剪贴板选择 :主要,辅助和剪贴板。 我们只关心主要对象和剪贴板。 中学旨在替代小学。
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "xclip -i -f -selection primary | xclip -i -selection clipboard"
Or when using xsel
:
或使用xsel
:
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "xsel -i --clipboard"
Read here about comparison of xclip
vs. xsel
, if you’re curious. Also, check out this post on xclip
usage and examples. And don’t forget to install one of these utilities, as they might not be a part of your distribution.
如果您感到好奇,请在此处阅读有关xclip
与xsel
比较。 另外,请查看有关xclip
用法和示例的帖子 。 并且不要忘记安装这些实用程序之一,因为它们可能不属于您的发行版。
So far we covered only local scenarios. When you SSH to remote machine, and start tmux sessions there, you cannot make use of pbcopy
, xclip
or xsel
, because text will be stored in the remote machine’s clipboard, not in your local one. You need some way to transport copied text to your local machine’s clipboard.
到目前为止,我们仅介绍了本地情况。 当SSH到远程计算机并在其中启动tmux会话时,您将无法使用pbcopy
, xclip
或xsel
,因为文本将存储在远程计算机的剪贴板中,而不是本地剪贴板中。 您需要某种方式将复制的文本传输到本地计算机的剪贴板。
ANSI escape sequence is a sequence of bytes sent to the terminal that are interleaved with regular printable characters, and are used to control various terminal aspects: such as text colors, cursor position, text effects, clearing screen. The terminal is capable of detecting such controlling sequence of bytes that causes it to trigger specific actions and not print those characters to the output.
ANSI转义序列是发送到终端的字节序列,与常规的可打印字符交织在一起,用于控制终端的各个方面:例如文本颜色,光标位置,文本效果,清除屏幕。 终端能够检测到这样的字节控制序列,该序列导致终端触发特定的操作,而不将那些字符打印到输出中。
The ANSI escape sequence can be detected as they start with ESC
ASCII character (0x1b hex, 027 decimal, \033 in octal). For example, when the terminal sees the \033[2A
sequence, it will move the cursor position 2 lines up.
可以检测到ANSI转义序列,因为它们以ESC
ASCII字符(十六进制为0x1b,十进制为027,八进制为\ 033)开头。 例如,当终端看到\033[2A
序列时,它将使光标位置向上移动2行。
There are really a lot of those known sequences. Some of them are the same across different terminal types, while others can vary and be very specific to your terminal emulator. Useinfocmp
command to query terminfo
database for escape sequences supported by different types of terminals.
确实 有很多已知的序列。 其中一些在不同的终端类型上是相同的,而另一些则可能有所不同,并且非常针对您的终端仿真器。 使用infocmp
命令可查询terminfo
数据库以获取不同类型的终端支持的转义序列。
Okay great, but how can it help us regarding the clipboard? It turns out that there is a special category of escape sequences: “Operating System Controls” (OSC) and the “OSC 52" escape sequence, which allows applications to interact with the clipboard.
好的,但是它对剪贴板有什么帮助? 事实证明,有一类特殊的转义序列:“操作系统控件”(OSC)和“ OSC 52”转义序列,它允许应用程序与剪贴板进行交互。
If you’re using iTerm, try to execute following command, and then “⌘V
” to see contents of system clipboard. Make sure to turn on OSC 52 escape sequence handling: “Preferences -> General -> Applications in terminal may access clipboard”.
如果您使用的是iTerm,请尝试执行以下命令,然后⌘V
“ ⌘V
”以查看系统剪贴板的内容。 确保打开OSC 52转义序列处理:“首选项->常规->终端中的应用程序可以访问剪贴板”。
printf "\033]52;c;$(printf "%s" "blabla" | base64)\a"
The conclusion is that we can store text in the system clipboard by sending a specially crafted ANSI escape sequence to our terminal.
结论是,可以通过向终端发送特制的ANSI转义序列来将文本存储在系统剪贴板中。
Let’s write the shell script yank.sh
:
让我们编写shell脚本yank.sh
:
#!/bin/bash
set -eu
# get data either form stdin or from filebuf=$(cat "$@")
# Get buffer lengthbuflen=$( printf %s "$buf" | wc -c )
maxlen=74994
# warn if exceeds maxlenif [ "$buflen" -gt "$maxlen" ]; then printf "input is %d bytes too long" "$(( buflen - maxlen ))" >&2fi
# build up OSC 52 ANSI escape sequenceesc="\033]52;c;$( printf %s "$buf" | head -c $maxlen | base64 | tr -d '\r\n' )\a"
So, we read text to copy from stdin
, then check if it’s length exceeds the maximum length of 74994 bytes. If true, we crop it, and finally convert data to base64 and wrap in OSC 52 escape sequence: \033]53;c;${data_in_base64}\a
因此,我们从stdin
读取要复制的文本,然后检查其长度是否超过了74994字节的最大长度。 如果为true,我们将其裁剪,最后将数据转换为base64并包装在OSC 52转义序列中: \033]53;c;${data_in_base64}\a
Then let’s wire it with our tmux keybindings. That’s pretty easy: just pipe the selected text to our yank.sh
script, just as we pipe it to pbcopy
or xclip
.
然后,将其与tmux键盘绑定连接起来。 这很容易:只需将选定的文本通过管道yank.sh
到yank.sh
脚本,就像将其通过管道传输到pbcopy
或xclip
。
yank="~/.tmux/yank.sh"
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "$yank"
However, there is one piece left to complete the puzzle. Where should we send the escape sequence? Apparently, just sending it to stdout
won’t work. The target should be our parent terminal emulator, but we don’t know the right tty
. So, we’re going to send it to tmux’s active pane tty
, and tell tmux to further resend it to the parent terminal emulator:
但是,还剩下一件完成这一难题。 我们应该在哪里发送转义序列? 显然,仅将其发送到stdout
行不通的。 目标应该是我们的父终端仿真器,但是我们不知道正确的tty
。 因此,我们将其发送到tmux的活动窗格tty
,并告诉tmux进一步将其重新发送到父终端仿真器:
# build up OSC 52 ANSI escape sequenceesc="\033]52;c;$( printf %s "$buf" | head -c $maxlen | base64 | tr -d '\r\n' )\a"esc="\033Ptmux;\033$esc\033\\"
pane_active_tty=$(tmux list-panes -F "#{pane_active} #{pane_tty}" | awk '$1=="1" { print $2 }')
printf "$esc" > "$pane_active_tty"
We use tmux list-panes
command to query for the active pane and it’s tty
. We also put our OSC 52 sequence in an additional wrapper escape sequence (Device Control String, ESC P), so tmux unwraps this envelope and passes OSC 52 to parent terminal.
我们使用tmux list-panes
命令查询活动窗格及其tty
。 我们还将OSC 52序列放入其他包装转义序列(设备控制字符串,ESC P)中,因此tmux会解包此信封并将OSC 52传递给父终端。
In newer versions of tmux, you can tell tmux to handle interactions with the clipboard for you. Seeset-clipboard
tmux option. on
— tmux will create an inner buffer and attempt to set the terminal clipboard using OSC 52. external
— do not create a buffer, but still attempt to set the terminal clipboard.
在新版本的tmux中,您可以告诉tmux为您处理与剪贴板的交互。 请参阅set-clipboard
tmux选项。 on
- TMUX将创建一个内部缓冲和尝试设置使用OSC 52.终端剪贴板external
-不创建的缓冲器,但仍尝试设置终端剪贴板。
Just make sure it’s either external
or on
:
只要确保它在external
或on
:
set -g set-clipboard on
So, if tmux is already capable of this feature, why we need to bother ourselves with manual wiring OSC 52 stuff? That’s because set-clipboard
does not work when you have a remote tmux session nested in a local one. And it only works in those terminals which supports OSC 52 escape sequence handling.
因此,如果tmux已经具备此功能,为什么我们需要手动布线OSC 52东西呢? 这是因为当在本地本地嵌套了一个远程tmux会话时, set-clipboard
不起作用。 并且它仅在支持OSC 52转义序列处理的终端中起作用。
The trick for nested remote sessions is to bypass the remote session and send our OSC 52 escape sequence directly to the local session, so it hits our local terminal emulator (iTerm).
嵌套远程会话的技巧是绕过远程会话,然后将我们的OSC 52转义序列直接发送到本地会话,这样它就会命中我们的本地终端模拟器(iTerm)。
Use $SSH_TTY
for this purpose:
$SSH_TTY
,请使用$SSH_TTY
:
# resolve target terminal to send escape sequence# if we are on remote machine, send directly to SSH_TTY to transport escape sequence# to terminal on local machine, so data lands in clipboard on our local machinepane_active_tty=$(tmux list-panes -F "#{pane_active} #{pane_tty}" | awk '$1=="1" { print $2 }')target_tty="${SSH_TTY:-$pane_active_tty}"
printf "$esc" > "$target_tty"
That’s it. Now we have a completely working solution, be it a local session, remote or both, nested in each other. Credits to this great post, where I first read about this approach.
而已。 现在我们有了一个完全可行的解决方案,无论是本地会话,远程会话还是两者都嵌套在一起。 归功于这篇很棒的文章 ,我在这里首先了解了这种方法。
The major drawback of using OSC escape sequences,is that despite being declared in spec, only a few terminals support this in practice: iTerm and xterm do, whereas OSX Terminal, Terminator, and Gnome terminal does not. So, an otherwise great solution (especially in remote scenarios, when you cannot just pipe
to xclip
or pbcopy
) lacks wider terminal support.
使用OSC转义序列的主要缺点是,尽管在规范中进行了声明,但实际上只有少数终端支持此功能:iTerm和xterm支持,而OSX终端,终结器和Gnome终端则不支持。 因此,另外一个很棒的解决方案(尤其是在无法仅通过pipe
传输到xclip
或pbcopy
远程方案中)缺少更广泛的终端支持。
You might want to checkout complete version of yank.sh
script.
There is yet another solution to support remote scenarios, which is rather crazy, and I’ll describe it in another dedicated post. The idea is to setup a local network listener which pipes input to pbcopy
or xclip
or xsel;
and pipes copied selected text from a remote machine to a listener on the local machine through SSH remote tunneling. Stay tuned.
还有另一种支持远程方案的解决方案,这非常疯狂,我将在另一篇专门的文章中对其进行描述。 这个想法是建立一个本地网络监听器,它将输入管道传输到pbcopy
或xclip
或xsel;
并通过SSH远程隧道将复制的选定文本从远程计算机传递到本地计算机上的侦听器。 敬请关注。
ANSI escape code — Wikipedia — https://en.wikipedia.org/wiki/ANSI_escape_code#Escape_sequences
ANSI转义代码— Wikipedia — https://en.wikipedia.org/wiki/ANSI_escape_code#Escape_sequences
What are OSC terminal control sequences / escape codes? | ivucica blog — https://blog.vucica.net/2017/07/what-are-osc-terminal-control-sequences-escape-codes.html
什么是OSC终端控制序列/转义码? | ivucica博客- https://blog.vucica.net/2017/07/what-are-osc-terminal-control-sequences-escape-codes.html
Copying to clipboard from tmux and Vim using OSC 52 — The Terminal Programmer — https://sunaku.github.io/tmux-yank-osc52.html
使用OSC 52从tmux和Vim复制到剪贴板—终端程序员— https://sunaku.github.io/tmux-yank-osc52.html
Copy Shell Prompt Output To Linux / UNIX X Clipboard Directly — nixCraft — https://www.cyberciti.biz/faq/xclip-linux-insert-files-command-output-intoclipboard/
将Shell提示符输出直接直接复制到Linux / UNIX X剪贴板— nixCraft — https://www.cyberciti.biz/faq/xclip-linux-insert-files-command-output-intoclipboard/
software recommendation — ‘xclip’ vs. ‘xsel’ — Ask Ubuntu — https://askubuntu.com/questions/705620/xclip-vs-xsel
软件推荐-'xclip'与'xsel'-询问Ubuntu- https: //askubuntu.com/questions/705620/xclip-vs-xsel
Everything you need to know about Tmux copy paste · rushiagr — http://www.rushiagr.com/blog/2016/06/16/everything-you-need-to-know-about-tmux-copy-pasting/
您需要了解的有关Tmux复制粘贴·rushiagr的所有信息— http://www.rushiagr.com/blog/2016/06/16/everything-you-need-to-know-about-tmux-copy-pasting/
macos — Synchronize pasteboard between remote tmux session and local Mac OS pasteboard — Super User — https://superuser.com/questions/407888/synchronize-pasteboard-between-remote-tmux-session-and-local-mac-os-pasteboard/408374#408374
macos —在远程tmux会话和本地Mac OS粘贴板之间同步粘贴板—超级用户— https://superuser.com/questions/407888/synchronize-pasteboard-between-remote-tmux-session-and-local-mac-os-pasteboard / 408374#408374
linux — Getting Items on the Local Clipboard from a Remote SSH Session — Stack Overflow — https://stackoverflow.com/questions/1152362/getting-items-on-the-local-clipboard-from-a-remote-ssh-session
linux-从远程SSH会话中获取本地剪贴板上的项目-堆栈溢出-https: //stackoverflow.com/questions/1152362/getting-items-on-the-local-clipboard-from-a-remote-ssh-session
Use tmux set-clipboard in gnome-terminal (XTerm’s disallowedWindowOps) — Ask Ubuntu — https://askubuntu.com/questions/621522/use-tmux-set-clipboard-in-gnome-terminal-xterms-disallowedwindowops/621646
在gnome-terminal中使用tmux set-clipboard(XTerm的disallowedWindowOps)—询问Ubuntu- https://askubuntu.com/questions/621522/use-tmux-set-clipboard-in-gnome-terminal-xterms-disallowedwindowops/621646
翻译自: https://www.freecodecamp.org/news/tmux-in-practice-integration-with-system-clipboard-bcd72c62ff7b/
tmux系统剪切板