Vim + COPY + Mac 通过 SSH

85

我通过ssh访问服务器,在其中运行vim编辑文件。当我尝试使用y或"+y将文本从vim复制到我的Mac(Lion)本地编辑器时,它无法正常工作。我最后得到的是我上次在本地复制的文本。但如果我在vim中使用p,则可以正常工作。


1
你是在使用Terminal.app还是其他终端程序? - pb2q
你能把名称改成vim + COPY + mac over SSH吗? - ningsuhen
1
七年后...答案是创建~/.vimrc并添加一行代码:set clipboard=unnamed。这适用于在Mac终端中使用Debian 10。 - frozenjim
在服务器上不应该使用vim打开大文件,这会占用很多内存。如果你想复制一些东西,比如一些答案,只需使用cat和grep命令查找文件中所需内容,并从终端复制即可。 - Hi computer
18个回答

84

进一步补充Ray的回答...

当你通过SSH使用Vim在远程服务器上时,你在Vim中进行的所有操作都是在远程服务器上完成的。远程服务器和你在其上运行的远程Vim实例对你本地计算机及其系统剪贴板几乎没有实际了解。

因此,y命令永远不会将复制的文本放入你的本地剪贴板。

为了将从远程Vim中复制的文本块复制到你本地计算机的剪贴板,你有三个选择:

  • 使用鼠标选择文本,然后像在任何Mac OS X应用程序中一样按下Cmd+C

    显然,这似乎是最简单的方法,但它至少有三个限制:

    1. 它限于当前屏幕。如果你要复制的文本未完全显示,你将无法复制全部内容。

    2. 它与set mouse=a设置不兼容。使用此选项时,尝试使用鼠标选择任何内容都将导致visual模式选择,无法使用Cmd+C复制。作为解决方法,你可以使用Alt+鼠标选择文本而不进入visual模式,或者从远程~/.vimrc文件中删除此设置。

    3. 行号也会被复制。

  • 将复制的文本放入临时文件中,使用scp将其传输到本地计算机,并使用pbcopy将其放入系统剪贴板。

    这个解决方案似乎有点复杂,但它是有效的(而且问题本身也有一点错综复杂)。多年来,我看过许多不同的实现,从简单的一行代码到客户端/服务器设置 (这里是其中之一),可以自由地在网络上搜索其他的实现方法。

  • 如果可用,使用X-forwarding将本地剪贴板连接到远程剪贴板。


1
谢谢Romaini - 我认为这是最接近的答案。看起来确实没有非常好的答案。我确实有mouse=a。我希望保留它。由于我还想保持nerd tree打开,按下Alt键不仅可以获得行号,还可以获得目录。任何一个都不好。我碰巧也使用Expanddrive mac。我将我的.vimrc和.vim目录移动到mac上,并通过sftp访问。无论我尝试什么,yank都不起作用 - 所以我放了这个hack“vmap y:w!pbcopy <CR> <CR>”。那工作得相当完美。奇怪的小错误是你只能复制完整的行... - evolution
2
实用提示:当使用“用鼠标选择文本”选项时,您可以使用:set nonum切换行号。 - Goodword
2
另一种方法,虽然有些繁琐但也能应急使用:退出 vim。从命令行输入 "cat" 文件名(键入 "cat <文件名>")。 现在你可以用鼠标复制了(使用 cmd-C)。 - Andrew Marshall
2
在某些操作系统中,当您使用鼠标选择文本以覆盖设置mouse=a时,需要按住Shift键而不是Alt键。 - bennlich
1
按住 alt 键,用鼠标选择,然后在 Mac 上使用 Cmd+C 很方便!谢谢! - fstang
显示剩余6条评论

44

遇到了这个问题——从OSX通过SSH登录到Linux服务器时,无法复制使用vim打开的文件中的文本。

我的解决方案是::set mouse=i

默认情况下,鼠标在所有模式下都是启用的。当你将它设置为仅在插入模式下启用时,你可以在不编辑(正常模式)时滚动和复制内容,但当你开始编辑(通过I或插入键)进入插入模式时,鼠标会充当光标位置,你无法从终端复制。

您可以在~/.vimrc中设置该选项。

有关您可以设置和模式的更多信息,请参见:help mouse。


使用 :set mouse=i 对我也起作用。没有指定任何与 mouse 相关的属性,使用鼠标选择文本会启用可视模式。仅运行 :set,这是唯一的鼠标设置:ttymouse=xterm2。请注意,在我运行 :set mouse=i 后,ttymouse=xterm2 仍然存在,但我能够使用鼠标选择文本并使用 Mac 剪贴板进行复制。 - Kaan
谢谢,这解决了我的问题。如果我想要调整分割,我必须切换鼠标 = a | i,但这很容易并且有效。 - jeremyjjbrown
@jeremyjjbrown,也许更好的方法是使用mouse=v,并在需要调整分割时按v切换到可视模式。 - TamaMcGlinn

32

我在stackoverflow上的第一个答案,但我觉得这是一个酷(虽然很小)的技巧,值得发布。所以这就是我做的:

cat <filename>

当文本被打印到终端上时,我使用鼠标选择所有文本(因为我们在终端窗口中,所以鼠标滚轮可用)。然后使用 Cmd+C 复制该文本,并粘贴到我的本地文本编辑器中。

这个技巧唯一的缺点是如果你的文件有成千上万行,使用鼠标选择所有行将是一项繁琐的任务。但对于大约2k行的文件,它运作良好。


如果有人想要粘贴而不是复制,请执行 !cat >> % 命令,然后进行粘贴,按下ctrl-C停止 cat。运行 :e! 命令,内容就会出现在文件的底部。 - jstaab
如果你只想从一个有2k行的文件中复制750到764行,你可以在vim命令行中输入! cat % | head -764 - OscarJ

25

我的常规解决方法是通过scp从本地机器使用vim编辑文件。

:e scp://remoteuser@server.tld//path/to/document

这样可以使你的缓冲区本地化,并且很容易复制到你的本地剪贴板。

另一个优点是你可以使用本地vim设置(.vimrc设置、插件等)


很棒的方法,可惜当你在SSH会话中的Docker容器shell内部时它无法工作。 - om-ha

13
iTerm2 Shell Utilities带有it2copy,允许从远程服务器复制到客户端剪贴板。在远程服务器上安装Shell Utilities,并确保选中“终端中的应用程序可以访问剪贴板”。然后进入“可视模式”,选择文本并执行“<,'>:w !it2copy”。enter image description here

有趣。我现在使用neovim而不是vim,但最近还没有尝试过这个。我会研究一下的。 - andrewgazelka
你如何在远程服务器上安装该命令? - David542
1
@David542,我回复有点晚了……你需要在服务器上安装Shell集成 - andrewgazelka
1
这似乎不起作用!我得到了 zsh:1: command not found: it2copy - Orif Milod
@MilodOrif,您是否在服务器上安装了Shell工具,并注销并重新登录? - andrewgazelka
2
@andrewgazelka 很抱歉回复晚了,是的我做了那个,但有一些成功,但我得到的测试以base64格式呈现。我已在iterm存储库中进行了PR,但没有太大的帮助:\ https://github.com/gnachman/iterm2-website/issues/81 - Orif Milod

9

https://github.com/ojroques/vim-oscyank + iTerm2 + tmux 在我的情况下可行,这是我的工作流程:

我的 .vimrc 的一些部分

Plug 'ojroques/vim-oscyank'  " clipboard over ssh through tmux

" yank operation don't need to use the *" register (system clipboard)
set clipboard+=unnamedplus

autocmd TextYankPost *
    \ if v:event.operator is 'y' && v:event.regname is '+' |
    \ execute 'OSCYankRegister +' |
    \ endif

3
嘿,这太棒了!我已经寻找解决方案有一段时间了。在运行iTerm的Mac上ssh到一个运行在tmux中的Linux服务器上使用vim完美地解决了我的问题。谢谢! - fatz
不幸的是,这对我不起作用。我在主机和客户端上都使用tmux。 如果我重新启动所有系统一段时间,它可以工作,但它总是停止工作。 - mstruebing

5

在通过ssh连接到终端的vi内部,使用yank命令会将所选行复制到远程机器上vi的内部缓冲区中,而非复制到您Mac电脑的剪贴板中。

此时您可以使用鼠标来进行复制。 :)


似乎应该有一种方法可以使用cmd+c,实际上我尝试了鼠标,但那并不是很有效,而且速度很慢。我相信一定有更好的方法... - evolution
是的,在终端窗口中,当vi运行时,拖动鼠标以突出显示要复制的文本。按Command+C,然后在Mac上的本地应用程序中,例如TextPad,按Command+V。 - Ray Toal
不起作用-那将是非常明显的。如果它能工作,我就不会在这里问了。当我用鼠标突出显示文本并右键单击时,它会返回到只选择我正在进行的特定工作。所以我只复制一个词。 - evolution
抱歉,我猜这应该很明显。我们可能有不同的配置,因为这对我来说确实有效。尝试一下romani的答案。祝好。 - Ray Toal
只要没有配置set mouse=a,它就能正常工作。真正的问题是复制行号或每次复制时都必须将其关闭。编辑远程文件也可以正常工作:http://vim.wikia.com/wiki/Editing_remote_files_via_scp_in_vim - None

4
在MacOS中,从机器A通过SSH连接到机器B并使用机器B上的vim时,我会在机器B的.vimrc文件中添加以下内容:
nmap yr :call system("ssh $machineA_IP pbcopy", @*)<CR>

这样,在正常模式下,如果你将某些内容复制到*寄存器中,然后输入yr,则假设你已经正确地使用+clipboard*寄存器设置了Vim,Vim @ machine_B的*寄存器的内容将被复制到机器A的本地剪贴板中。


3
这是关于romainl的解决方案#2的最新更新。它创建了ssh命令的别名,并在远程拷贝服务器未运行时启动该服务器,并在远程服务器上安装了远程拷贝(rclip)。简而言之,您只需要将下面的代码片段粘贴到bash_profile中,无需做任何其他操作。
######################## For SSH Remote Copy #########################
export LC_SETUP_RC='command -v rclip >/dev/null 2>&1 || { echo "executing"; mkdir -p /usr/local/bin; if [ ! -f /usr/local/bin/rclip ];then wget https://raw.githubusercontent.com/justone/remotecopy/master/remotecopy -P /usr/local/bin/; ln -s /usr/local/bin/remotecopy /usr/local/bin/rclip; chmod +x /usr/local/bin/remotecopy; fi; if [[ \":\$PATH:\" == *\"/usr/local/bin:\"* ]]; then export PATH=/usr/local/bin:$PATH; fi } > /var/log/rclip.log 2>&1 || echo "Some error occured in setting up rclip. check /var/log/rclip.log"'

ssh_function() {
count="`ps -eaf | grep remotecopyserver | grep -v grep | wc -l`";
if [ "$count" -eq "0" ]; then 
   mkdir -p $HOME/bin;
   if [ ! -f $HOME/bin/remotecopyserver ]; then 
      wget https://raw.githubusercontent.com/justone/remotecopy/master/remotecopyserver -P $HOME/bin;
      chmod +x $HOME/bin/remotecopyserver;
   fi;
   nohup $HOME/bin/remotecopyserver & 
fi;
ssh_cmd=`which ssh`
PARAMS=""
for PARAM in "$@"
do
  PARAMS="${PARAMS} \"${PARAM}\""
done
bash -c "ssh ${PARAMS} -R 12345:localhost:12345 -t 'echo \$LC_SETUP_RC | sudo bash; bash -l'"
}
alias ssho=`which ssh`
alias ssh=ssh_function
alias ssh2=ssh_function

vssh_function() {
ssh_config=`vagrant ssh-config`;
if [ "$?" -eq "1" ]; then
echo "Problem with Vagrant config. run 'vagrant ssh-config' to debug"
return 1
fi
PORT=`echo "$ssh_config" | grep Port | grep -o "[0-9]\+"`; 
ID_FILE=`echo "$ssh_config" | grep IdentityFile | awk '{print $2}'`
ssh2 -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o PasswordAuthentication=no -i $ID_FILE vagrant@localhost -p $PORT "$@"
}
alias vssh=vssh_function

激活别名后,您可以正常使用ssh,每当您需要从vim复制到本地剪贴板时,请使用

:w !rclip 

复制整个文件到剪贴板

:'<,'> !rclip

从可视模式复制选定的行。每当它要求输入密钥时,您必须按下“Cmd+V”或“Ctrl + V”。

奖励

对于那些在Vagrant上工作的人,有一个包装器vssh,它将执行vagrant ssh ,但还会启动并安装必要的组件。

参考

最新代码片段在此处 - https://gist.github.com/ningsuhen/7933b206b92fc57364b2

http://endot.org/2011/12/04/remotecopy-copy-from-remote-terminals-into-your-local-clipboard/

https://github.com/justone/remotecopy

注意事项

别名包装了ssh命令,可能会出现一些意外问题。如果需要执行不带整个remotecopyserver的ssh,则可以使用ssho。或者,您可以使用别名ssh2,并保持ssh命令不变。


3

Mac + SSH + iTerm2 + Neovim 操作指南:

  1. 使用 SSH 登录服务器。
  2. 安装 iTerm shell integration
  3. ~/.iterm2 添加到 $PATH 变量中。
  4. 在例如 ~/.local/bin 中创建一个 ttyup 命令。
  5. 如果还没有,请将 ~/.local/bin 添加到 $PATH
  6. g:clipboard 声明添加到您的 init.vim 文件中。

ttyup

#!/bin/bash
# @medgar's ttyup script for passing the output to the parent shell

parent() { awk '{print $4}' "/proc/$1/stat"; }
leader() { awk '{print $6}' "/proc/$1/stat"; }
it2copy > "/proc/$(parent $(leader $$))/fd/0"

init.vim:

let g:clipboard = {
\   'name': 'myClipboard',
\   'copy': {
\      '+': ['ttyup'],
\      '*': ['ttyup'],
\   },
\   'paste': {
\      '+': '+',
\      '*': '*',
\   },
\   'cache_enabled': 0,
\ }

这个功能真的很好用!当我使用 y 剪切一些内容时,它会将其填充到我的本地 Mac 剪贴板中。唯一的问题是,当我使用 p 在远程 vim 中粘贴内容时,会出现以下错误:Error detected while processing function provider#clipboard#Call[9]..function provider#clipboard#Call[6]..268[7]..<SNR>35_try_cmd: E475: Invalid value for argument cmd: '+' is not executable。目前我只是忽略了这个错误。 - Xander Dunn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接