106

There are two command-line tools (in two different packages) to access the X clipboard:

  • xclip
  • xsel

I would love to know the difference between those two and hear a recommendation which one to use in which cases.

Byte Commander
  • 110,243

7 Answers7

59

Both xclip and xsel can store text into 3 different selections (by default it is primary selection). From experience I know that primary selection is basically what you high-light and released with the middle mouse click (which corresponds to pressing both right and left touchpad key on a laptop). The clipboard is the traditional CtrlV.

By examining the man pages for both, however, I've discovered that xclip wins in one aspect - reading from an input file:

$ 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)

Of course you could use shell redirection with xsel to get around that

$ xsel --clipboard < testfile.txt

$ HELLOWORLD mksh: HELLOWORLD: not found

xclip also wins in the fact that you can output the contents of clipboard to file (which is perhaps useful when you want to redirect PRIMARY selection , i.e. highlights). xsel offers only output to stdout

43

In addition to @Serg answer, there is a piece of information from the Tmux page in the Arch Wiki that can be useful in some specific cases:

Unlike xsel [xclip] works better when printing a raw bitstream that does not fit the current locale. Nevertheless, it is neater to use xsel because xclip does not close STDOUT after it has read from the tmux buffer. As such, tmux does not know that the copy task has completed, and continues to wait for xclip to terminate, thereby rendering tmux unresponsive. A workaround is to redirect STDOUT to /dev/null:

Pablo Bianchi
  • 17,371
31

Something else to keep in mind, xsel has fewer dependencies than 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
Martin K
  • 566
  • 5
  • 7
16

Use xclip, because xsel can not extract binary data from clipboard, such as screenshots. For example, save screenshot to clipboard:

$ maim -s | xclip -selection clipboard -t image/png

Then save to file and compare output:

$ xclip -o -selection clipboard > 1xclip
$ xsel -o --clipboard > 1xsel
$ ls -go 1*
-rw-rw-r-- 1 11948 Sep 26 20:13 1xclip
-rw-rw-r-- 1     0 Sep 26 20:13 1xsel
guntbert
  • 13,475
2

There is one other reason to use xclip over xsel – xclip can manipulate cut buffer 0, by passing -selection buffer-cut, which xsel cannot do.

It's relatively easy to allow it to manipulate the other cut buffers as well; here is my patch, though it's not well-tested and comes with no guarantees.

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);

ash
  • 2,207
0

For me xclip will let zsh shell exit very slowly when using guake.

Like run command: $ pwd | xclip -selection c. Then run $ exit to quit shell.

$ exit need seconds to quit.

xsel is good with this situation.

0

xclip has this special feature to remove last empty line of copied selection where xsel don't have this option.

man xclip

-rmlastnl remove the last newline charater if present

Akhil
  • 646