在Bash脚本中将数据传输到/从剪贴板的管道

1289

在Bash中是否可以将内容导入/导出到剪贴板?

无论是将内容导入/导出到设备句柄,还是使用辅助应用程序,我都没有找到任何相关资料。

例如,如果/dev/clip是指向剪贴板的设备链接,我们可以这样做:

cat /dev/clip        # Dump the contents of the clipboard
cat foo > /dev/clip  # Dump the contents of "foo" into the clipboard

6
我一直在使用 :%y+ 命令来复制所有行到 X 的 PRIMARY 剪贴板中,其中 X 代表的是 '+' 寄存器。如果您想要具体指定某些行,请将 % 替换为一个范围。但是,这里有三个注意事项:1. 现在,您必须先将文本保存到文件中才能复制它。这与答案中提到的 xclip 命令相反。2. 如果您不熟悉 vim,这可能会很繁琐。3. 只有在编译 vim 时启用了特定功能才能执行此操作。如果您安装了 GVim,则默认情况下应该在 vim 的 GUI 和终端实例中启用该功能。 - Braden Best
1
@BradenBest 你应该将此作为答案提交。我在一个 NIX 环境下,无法安装 xclip。你的回答非常好用。 - HankCa
@HankCa 好的,我发布了一个答案。告诉我你的想法。 - Braden Best
@BradenBest 给出了非常全面的答案。虽然我只喜欢 :%y+ 这个方法,但没关系,你已经覆盖了所有情况!干得好。 - HankCa
我对于复制例如ls输出的简单解决方案是:ls | xclip -i -selection clipboard - user2585716
显示剩余2条评论
32个回答

5

在Linux中,这是有效的:

cat filename | xclip

1
但是已经被之前的回答覆盖了,对吧? - Peter Mortensen
1
@PeterMortensen 是的和不是。当阅读 https://dev59.com/PnRB5IYBdhLWcg3wAjRH#4208191 和 https://dev59.com/PnRB5IYBdhLWcg3wAjRH#27456981 时,您可能认为需要创建一个别名,如 alias xclip="xclip -selection c"。但是 xclip 似乎不需要这个别名,也可以参见 How to pipe text from command line to the clipboard - Super User 在 2010 年的文章。 - questionto42

4
有几种方法。其中一些已经提到了,包括(我想)tmuxScreenVimEmacs和shell。我不知道Emacs或Screen,所以我来介绍其他三个。

Tmux

虽然不是X选择,但tmux具有可通过prefix-[(默认情况下prefix Ctrl +B)访问的复制模式。用于此模式的缓冲区是独立且专属于tmux,这在正确的情况下打开了许多可能性,并使其更加多功能。
要退出此模式,请按Q; 要导航,请使用您的Vim或Emacs绑定(默认= Vim),所以使用hjkl进行移动,使用v/V/C-v进行字符/行/块选择等。当您选择完成后,按Enter复制并退出该模式。
要从此缓冲区粘贴,请使用prefix-]

Shell

任何X11的安装似乎都默认带有两个程序:xclipxsel(有点像它也带有startxxinit)。大多数其他答案都提到了xclip,而我非常喜欢xsel的简洁性,因此我将介绍xsel
来自xsel(1x)

输入选项

-a, --append

将标准输入追加到选择中。意味着-i

-f, --follow

随着标准输入的增长,将其附加到选择中。意味着-i

-i, --input

将标准输入读入选择中。

输出选项

-o, --output

将选择写入标准输出。

操作选项

-c, --clear

清除选择。覆盖所有输入选项。

-d, --delete

请求删除当前选择。这不仅清除了选择,还请求所在程序删除所选内容。覆盖所有输入选项。

选择选项

-p, --primary

操作PRIMARY选择(默认)。

-s, --secondary

操作SECONDARY选择。

-b, --clipboard

操作CLIPBOARD选择。

这就是您需要知道的全部内容了。对于 PRIMARY,使用 p(或不使用任何字符);对于 SECONDARY,使用 s;对于 CLIPBOARD,使用 b;对于输出,使用 o

例如:假设我想要将 TTY 中 foo 的输出复制到一个网页上以进行错误报告。为此,最好从 TTY/X 会话中复制/粘贴。所以问题变成了“我如何从 TTY 访问剪贴板?”

在这个例子中,我们假设 X 会话在显示器 :1 上。

$ foo -v
Error: not a real TTY
details:
blah blah @ 0x0000000040abeaf4
blah blah @ 0x0000000040abeaf8
blah blah @ 0x0000000040abeafc
blah blah @ 0x0000000040abeb00
...
$ foo -v | DISPLAY=:1 xsel -b # copies it into clipboard of display :1

然后我可以像往常一样将其通过 Ctrl + V 粘贴到表单中。

现在假设支持网站上有人给了我一个运行命令来解决问题。它很复杂且很长。

$ DISPLAY=:1 xsel -bo
sudo foo --update --clear-cache --source-list="http://foo-software.com/repository/foo/debian/ubuntu/xenial/164914519191464/sources.txt"
$ $(DISPLAY=:1 xsel -bo)
Password for braden:
UPDATING %%%%%%%%%%%%%%%%%%%%%%% 100.00%
Clearing cache...
Fetching sources...
Reticulating splines...
Watering trees...
Climbing mountains...
Looking advanced...
Done.
$ foo
Thank you for your order. A pizza should arrive at your house in the next 20 minutes. Your total is $6.99

披萨订购似乎是命令行的一个有益用途。

...继续。

Vim

如果使用+clipboard编译(这很重要!检查vim --version),Vim应该可以访问X PRIMARYCLIPBOARD选择。这两个选择可以从*+寄存器中访问,可以像其他寄存器一样随意写入和读取。

例如:

:%y+    ; copy/yank (y) everything (%) into the CLIPBOARD selection (+)
"+p     ; select (") the CLIPBOARD selection (+) and paste/put it
ggVG"+y ; Alternative version of the first example

如果你的Vim版本不支持直接访问X选择,也不必太过担心。你可以使用最后一节中描述的xsel技术来解决问题。
:r ! xsel -bo ; read  (r) from the stdout of (!) `xsel -bo`
:w ! xsel -b  ; write (w) to the stdin of    (!) `xsel -b`

绑定几个快捷键,你就可以了。


在从非X环境调用X应用程序时,一定要记得使用DISPLAY=。 X应用程序需要DISPLAY环境变量来确定它们正在与哪个服务器(或者只有一个服务器处理多个会话?)通信。例如,在TTY中尝试DISPLAY=:1 firefox(或者您的显示ID可能是什么;我的显示ID恰好是:1)。 - Braden Best
对我来说,在VIM中选择的命令是 :%y+ - HankCa
Xubuntu 22.04.3 LTS 默认情况下未安装 xselxclip - undefined

2
我写了几个年前的Windows程序。它们允许您转储、推送、追加和打印剪贴板。它的工作原理如下:
dumpclip | perl -pe "s/monkey/chimp/g;" | pushclip

它包含源代码:cmd_clip.zip


链接已失效。太遗憾了。 - Adrian

2
昨天我遇到了这样一个问题:“如何在不同的用户会话之间共享剪贴板?”当使用Ctrl + Alt + F7 - Ctrl + Alt + F8 之间切换会话时,实际上你无法粘贴你所复制的内容。
我想到了以下的“快捷且简单”的解决方案,基于命名管道。它确实相当原始和简陋,但我发现它很实用:
user1@host:~$ mkfifo /tmp/sharedClip

然后在发送终端

user1@host:~$ cat > /tmp/sharedClip

最后,在接收端:
user2@host:~$ cat /tmp/sharedClip

现在,您可以在第一个终端中键入或粘贴任何内容,然后(按下“Return”键后),它将立即出现在接收终端中,您可以从那里复制并再次粘贴到任何地方。
当然,这不仅仅是严格地将用户1的剪贴板内容提供给用户2的剪贴板,而是需要额外的一对“粘贴”和“复制”点击操作。

似乎并不令人惊讶。两个不同的X服务器=两个不同的选择集。但是,您可以设置一个脚本,通过xsel/xclip进行输入/输出。例如,一端监听以查看是否更改了任何选择,然后自动将其(通过命名的FIFO)传输到另一个脚本,该脚本正在侦听一个或多个管道,将其插入到自己的X选择中。因此,复制文本将自动导致相同的文本出现在其他X会话的选择中。别忘了$DISPLAY - Braden Best

2

从这个帖子中,有一个选项不需要安装任何第三方软件gclip/xclip/xsel

一个Perl脚本(因为Perl通常已经安装)

use Win32::Clipboard;
print Win32::Clipboard::GetText();

我该如何使用它?将脚本保存到路径中并将其管道传递给它吗?我正在尝试编写Dropbox CLI包装器以复制共享链接,因此我只需要它处理文本即可。 - jena
@jena 示例:https://metacpan.org/pod/Win32::Clipboard 或 https://www.perlmonks.org/?node_id=143637 或 http://www.bribes.org/perl/docfr/win32clipboard.html。 - VonC
无法在git bash上工作(cpan已损坏,无法下载任何内容),也无法在MSYS2上工作(cpan尝试了,但表示该操作系统不受支持)。 - Adrian
@Adrian True。对于Windows(即使是从Git bash会话中),我会调用一个可执行文件(在Go中编译),该文件使用win32 DLL调用来读取Windows剪贴板。这样,我就可以复制/粘贴了。 - VonC

2
Ruby oneliner激发了我尝试使用Python。
假设我们想要一个命令,将剪贴板中的任何内容缩进四个空格。这对于在Stack Overflow上分享代码片段非常完美。
$ pbpaste | python -c "import sys
 for line in sys.stdin:
   print(f'    {line}')" | pbcopy

这不是打字错误。Python需要换行符来执行for循环。我们想要一次性更改这些行以避免在内存中构建额外的数组。

如果您不介意构建额外的数组,请尝试:

$ pbpaste | python -c "import sys; print(''.join([f'    {l}' for l in sys.stdin]))" | pbcopy

但是说实话,相对于 Python,awk 更适合这个。我在我的 ~/.bashrc 文件中定义了这个别名。
alias indent="pbpaste | awk '{print \"    \"\$0}' | pbcopy"

现在,当我运行indent时,剪贴板中的任何内容都会被缩进。

1
你可以直接去掉括号,使用生成器表达式代替列表推导式。''.join(f' {l}' for l in sys.stdin) -- 对于大多数人来说,在 MacOS 上 python 将指向 python2。因此,你可能需要指定 python3 - sytech
什么是“Ruby oneliner”?你指的是什么?另一个答案?还是其他什么?请通过编辑(更改)您的答案来回复,而不是在评论中回复(不要包含“编辑:”,“更新:”或类似内容 - 答案应该看起来像今天写的)。 - Peter Mortensen
@HarryMoreno :我通常只使用列表推导式。就像我标准的shell函数将UTF8规范化为NFC形式一样,我使用的命令是 python3 -c 'import sys; import unicodedata as __; ___ = ""; [ print(__.normalize("NFC", _), end = ___) for _ in sys.stdin ]'。这些烦人的反斜杠代表一个字面上的反斜杠'\',后面跟着\n,因为python喜欢抱怨缩进,这使得使用4个shell一行命令非常不方便。 - undefined

1
在 macOS 中,使用 pbpaste 命令。
例如:
更新剪贴板
pbpaste  | ruby -ne ' puts "\|" + $_.split( )[1..4].join("\|") ' | pbcopy

1
使用除echo之外的任何工具,将剪贴板中的内容粘贴到文件中的方法。
  1. 转义要粘贴的文本中的单引号:将所有出现的'替换为'\''并将结果复制到剪贴板。
  2. 键入echo -n '
  3. 按下Shift+Insert
  4. 键入' > filename.txt
  5. 按下Enter
基本上你正在做这个: echo -n '带有 '\''单引号'\'' 转义的 "文本" 已复制' > filename.txt 即使复制的文本包含换行符,也可以正常工作。

Shift+Insert 是访问剪贴板的快捷键。 - user1529413

1

对于 mac,您可以使用以下函数来使用 pbcopypbpaste,但是更简单:

将以下内容添加到您的 .bashrc.zshrc 文件中:

clp() {
  if [[ -z "$1" ]]
  then
    # No input - act as paste
    pbpaste;
  else
    # Input exists - act as copy
    echo "$1" | pbcopy;
  fi
}

复制请使用clp "内容",粘贴请使用clp


0

如果你和我一样在没有root权限的Linux服务器上运行,并且没有xclipGPM,那么你可以通过使用临时文件来解决这个问题。例如:

$ echo "Hello, World!" > ~/clip
$ echo `cat ~/clip`
Hello, World!

我不明白缺少 root 权限如何影响这个问题。 - Braden Best
4
缺少根权限意味着我无法安装东西。 - horta
但是你要安装什么?X?在服务器上?除非你正在托管一些奇怪的X转发服务,否则我看不出为什么你会想这样做。 - Braden Best
1
@BradenBest 不确定。任何可以让我执行复制粘贴的程序或服务。 - horta
1
如果您正在使用任何X选择(这必然暗示了“剪贴板”和任何有关xclip / xsel的提及),则需要一个活动的X会话(因此需要X服务器)才能首先访问选择。要了解我的意思,请尝试在本地计算机上运行DISPLAY =“” xsel。它将因无法找到会话“”而退出错误,并且不会进行与任何X选择的交互。这就是为什么我最初说我不知道根权限如何影响此事的原因:无论有没有根,您都不太可能在服务器环境中找到X选择有用。 - Braden Best

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