'xclip' 与 'xsel'

'xclip' 与 'xsel'

有两个命令行工具(在两个不同的包中)可以访问 X 剪贴板:

  • xclip
  • xsel

我很想知道这两者之间的区别,并听取在什么情况下使用哪一种的建议。

答案1

xclip和都xsel可以将文本存储到3 种不同选择(默认情况下它是主要选择)。根据我的经验,主要选择基本上是您突出显示并通过鼠标中键单击释放的内容(这相当于在笔记本电脑上同时按下左右触摸板键)。剪贴板是传统的CtrlV

然而,通过检查这man两个页面,我发现它xclip在一个方面胜出 - 从输入文件中读取:

$ cat testfile.txt                                                             
HELLOWORLD

$ xclip -selection clipboard testfile.txt

$ HELLOWORLD
mksh: HELLOWORLD: not found

$ xsel testfile.txt 
Usage: xsel [options]
Manipulate the X sele . . . (usage page goes on)

当然,你可以使用 shell 重定向来xsel解决这个问题

$ xsel --clipboard < testfile.txt                                              

$ HELLOWORLD
mksh: HELLOWORLD: not found

xclip另一个优势是你可以把剪贴板的内容输出到文件(当你想要重定向主要选择,即突出显示时,这也许很有用)。 xsel仅提供输出到 stdout

答案2

除了@Serg回答,有一条信息来自Arch Wiki 中的 Tmux 页面在某些情况下可能有用具体案例

与 xsel 不同,[xclip] 在打印不适合当前语言环境的原始比特流时效果更好。不过,使用 xsel 更简洁因为 xclip 没有关闭STDOUT从 tmux 缓冲区读取后。因此,tmux 不知道复制任务已完成,并继续等待 xclip 终止,从而导致 tmux 无响应。一种解决方法是重定向STDOUT/dev/null

答案3

需要记住的另外一点是,xsel依赖关系比以下更少xclip

# apt-cache depends xsel
xsel
  Depends: libc6
  Depends: libx11-6
  Conflicts: xsel:i386

# apt-cache depends xclip
xclip
  Depends: libc6
  Depends: libx11-6
  Depends: libxmu6
  Conflicts: xclip:i386

答案4

使用 xclip 而不是 xsel 还有一个原因——xclip 可以通过传递来操作剪切缓冲区 0,-selection buffer-cut而 xsel 无法做到这一点。

让它操作其他切割缓冲区也相对容易;这是我的补丁,尽管它没有经过充分测试并且没有任何保证。

diff --git a/xclip.c b/xclip.c
index 5fc760cb7..eeb05f662 100644
--- a/xclip.c
+++ b/xclip.c
@@ -35,11 +35,12 @@
 #include "xclib.h"

 /* command line option table for XrmParseCommand() */
-XrmOptionDescRec opt_tab[14];
+XrmOptionDescRec opt_tab[15];

 /* Options that get set on the command line */
 int sloop = 0;         /* number of loops */
 char *sdisp = NULL;        /* X display to connect to */
+int bufnum = 0;        /* Cut buffer number to use */
 Atom sseln = XA_PRIMARY;   /* X selection to work with */
 Atom target = XA_STRING;

@@ -165,6 +166,9 @@ doOptSel(void)
        break;
    case 'b':
        sseln = XA_STRING;
+       if (XrmGetResource(opt_db, "xclip.buffer", "Xclip.Buffer", &rec_typ, &rec_val)) {
+           bufnum = atoi(&rec_val.addr[0]);
+       }
        break;
    }

@@ -177,8 +181,10 @@ doOptSel(void)
        fprintf(stderr, "XA_SECONDARY");
        if (sseln == XA_CLIPBOARD(dpy))
        fprintf(stderr, "XA_CLIPBOARD");
-       if (sseln == XA_STRING)
+       if (sseln == XA_STRING) {
        fprintf(stderr, "XA_STRING");
+       fprintf(stderr, "\nUsing buffer number %d", bufnum);
+       }

        fprintf(stderr, "\n");
    }
@@ -276,7 +282,7 @@ doIn(Window win, const char *progname)

     /* Handle cut buffer if needed */
     if (sseln == XA_STRING) {
-   XStoreBuffer(dpy, (char *) sel_buf, (int) sel_len, 0);
+   XStoreBuffer(dpy, (char *) sel_buf, (int) sel_len, bufnum);
    return EXIT_SUCCESS;
     }

@@ -445,7 +451,7 @@ doOut(Window win)
     unsigned int context = XCLIB_XCOUT_NONE;

     if (sseln == XA_STRING)
-   sel_buf = (unsigned char *) XFetchBuffer(dpy, (int *) &sel_len, 0);
+   sel_buf = (unsigned char *) XFetchBuffer(dpy, (int *) &sel_len, bufnum);
     else {
    while (1) {
        /* only get an event if xcout() is doing something */
@@ -595,6 +601,11 @@ main(int argc, char *argv[])
     opt_tab[13].argKind = XrmoptionNoArg;
     opt_tab[13].value = (XPointer) xcstrdup(ST);

+    opt_tab[14].option = xcstrdup("-buffer");
+    opt_tab[14].specifier = xcstrdup(".buffer");
+    opt_tab[14].argKind = XrmoptionSepArg;
+    opt_tab[14].value = (XPointer) NULL;
+
     /* parse command line options */
     doOptMain(argc, argv);

相关内容