xclip 在交互式和非交互式 shell 中的工作方式不同

xclip 在交互式和非交互式 shell 中的工作方式不同

在调查中描述的问题时stackoverflow 上的一个问题我将其简化为一个测试用例,证明在非交互模式下 bash 似乎在退出之前清除了 X 系统剪贴板。该测试打开一个 gnome 终端并在其中运行一个 bash 脚本,该脚本将(通过xclip)一些文本放入 X 系统剪贴板中。当终端打开时,查询剪贴板会返回放置在其中的文本,无论 bash 是以交互模式还是非交互模式运行。但是,在终端关闭后,如果 bash 以交互模式运行,则剪贴板内容会保留下来,但如果 bash 以非交互模式运行,则剪贴板内容会丢失。

$ cat xclip_test 
#!/usr/bin/env bash
set -x
gnome-terminal -x bash -i -c "echo abc|xclip -selection clipboard; sleep 3"
sleep 1
xclip -o -selection clipboard
sleep 4
xclip -o -selection clipboard
gnome-terminal -x bash -c "echo 123|xclip -selection clipboard; sleep 3"
sleep 1
xclip -o -selection clipboard
sleep 4
xclip -o -selection clipboard

$ ./xclip_test
+ gnome-terminal -x bash -i -c 'echo abc|xclip -selection clipboard; sleep 3'
+ sleep 1
+ xclip -o -selection clipboard
abc
+ sleep 4
+ xclip -o -selection clipboard
abc
+ gnome-terminal -x bash -c 'echo 123|xclip -selection clipboard; sleep 3'
+ sleep 1
+ xclip -o -selection clipboard
123
+ sleep 4
+ xclip -o -selection clipboard
Error: target STRING not available            #!!!!!!!!!!!!!

我使用的是 Ubuntu 16.04,使用默认的 GNU bash ( version 4.3.46(1)-release (x86_64-pc-linux-gnu)),没有对 bash rc 文件进行自定义。.bash_logout为了以防万一,我检查了一下,发现有一个对clear_console实用程序的调用。然而clear_console似乎不处理剪贴板;此外,该示例不将 bash 作为登录 shell 运行。

这有合理的解释吗?

编辑

gnome-terminal替换为以下内容时问题仍然存在xterm

gnome-terminal -x... --> xterm -e...&

而且它并不是唯一的bash- 它也被复制dash

答案1

该书的作者原问题 在 Stackoverflow 上已确定这是 xclip 中的问题。使用xsel代替xclip用于操作 X 剪贴板消除了该问题(请注意,仅xclipxsel放置数据进入剪贴板,而不是当读自剪贴板):

$ cat xclip_test 
#!/usr/bin/env bash
set -x
xterm -e bash -c "echo abc|xclip -selection clipboard; sleep 3"&
sleep 1
xclip -o -selection clipboard
sleep 4
xclip -o -selection clipboard

$ cat xsel_test 
#!/usr/bin/env bash
set -x
xterm -e bash -c "echo abc|xsel --input --clipboard; sleep 3"&
sleep 1
xclip -o -selection clipboard
sleep 4
xclip -o -selection clipboard

$ diff xclip_test xsel_test 
3c3
< xterm -e bash -c "echo abc|xclip -selection clipboard; sleep 3"&
---
> xterm -e bash -c "echo abc|xsel --input --clipboard; sleep 3"&


$ ./xclip_test 
+ sleep 1
+ xterm -e bash -c 'echo abc|xclip -selection clipboard; sleep 3'
+ xclip -o -selection clipboard
abc
+ sleep 4
+ xclip -o -selection clipboard
Error: target STRING not available     # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

$ ./xsel_test 
+ sleep 1
+ xterm -e bash -c 'echo abc|xsel --input --clipboard; sleep 3'
+ xclip -o -selection clipboard
abc
+ sleep 4
+ xclip -o -selection clipboard
abc

xclip和两者都xsel通过从终端分离并生成一个子进程来工作,该子进程负责按需提供选择(直到做出新选择):

$ ps -H
  PID TTY          TIME CMD
24307 pts/12   00:00:01 bash
27476 pts/12   00:00:00   ps
$ echo qwerty|xclip -selection clipboard
$ ps -H
  PID TTY          TIME CMD
27481 pts/12   00:00:00 xclip  <-- !!!!!!
24307 pts/12   00:00:01 bash
27482 pts/12   00:00:00   ps

问题似乎xclip是,当从非交互式外壳启动时,它不会完全独立于控制终端,并且会在终端进程退出时终止。

答案2

实际上,不存在X“系统剪贴板”。 X 中的选择由两个 X 客户端合作进行:一个 X 客户端声称它有一个选择(主要、次要、剪贴板),而另一个想要粘贴选择的 X 客户端联系第一个客户端以接收它。

因此,当第一个客户去世时,就没有选择了。然而,我不确定 bash 交互模式如何转换为“终端/bash 仍然可以响应”。做一个ps可能有助于解决问题。

这同样适用于剪贴板选择,除非xclipboard您同时运行该程序(或类似的程序),该程序接管提供选择的责任。 (参见例如维基百科文章)。

还有存储为根窗口属性的剪切缓冲区,您可以使用它们来存储永久内容。

答案3

pass我在 中遇到了同样的问题eshell。该pass程序使用xclip,它以与您提到的相同的方式失败。

我的解决方案是创建一个包装器脚本,该脚本也在xclip我的 PATH 中 /usr/bin 前面的位置命名,其中包含以下内容:

#!/bin/sh
exec setsid /usr/bin/xclip "$@"

答案4

我使用 xclip -i 遇到了这个或类似的问题。脚本结尾为

echo $totp | xclip -i -r

在 shell 提示符下可以正常运行,但是当脚本用于命令替换时,

totp=$(get-totp)

xclip 会挂起。关闭它的标准输出可以解决这个问题:

echo $totp | xclip -i -r >&-

相关内容