26

For example, if a python script will spit out a string giving the path of a newly written file that I'm going to edit immediately after running the script, it would be very nice to have it directly sent to the system clipboard rather than STDOUT.

NullUserException
  • 83,810
  • 28
  • 209
  • 234
nye17
  • 12,857
  • 11
  • 58
  • 68

4 Answers4

31

You can use an external program, xsel:

from subprocess import Popen, PIPE
p = Popen(['xsel','-pi'], stdin=PIPE)
p.communicate(input='Hello, World')

With xsel, you can set the clipboard you want to work on.

  • -p works with the PRIMARY selection. That's the middle click one.
  • -s works with the SECONDARY selection. I don't know if this is used anymore.
  • -b works with the CLIPBOARD selection. That's your Ctrl + V one.

Read more about X's clipboards here and here.

A quick and dirty function I created to handle this:

def paste(str, p=True, c=True):
    from subprocess import Popen, PIPE

    if p:
        p = Popen(['xsel', '-pi'], stdin=PIPE)
        p.communicate(input=str)
    if c:
        p = Popen(['xsel', '-bi'], stdin=PIPE)
        p.communicate(input=str)

paste('Hello', False)    # pastes to CLIPBOARD only
paste('Hello', c=False)  # pastes to PRIMARY only
paste('Hello')           # pastes to both

You can also try pyGTK's clipboard :

import pygtk
pygtk.require('2.0')
import gtk

clipboard = gtk.clipboard_get()

clipboard.set_text('Hello, World')
clipboard.store()

This works with the Ctrl + V selection for me.

Community
  • 1
  • 1
NullUserException
  • 83,810
  • 28
  • 209
  • 234
  • I tested this snippet but it seems it doesn't work for my settings. After doing `python abovescript.py`, then I middle-clicked my mouse in the terminal, but no `Hello, World` shows up. – nye17 Sep 30 '11 at 05:01
  • @nye17 Which method are you trying? Does it give you any errors? – NullUserException Sep 30 '11 at 05:03
  • 1
    The first `clipboard` one, doesn't work but no errors reported at all. – nye17 Sep 30 '11 at 05:04
  • There are two different clipboards in most Linux systems - the middle click and the `ctrl+c`/`ctrl+v` clipboards. check the other one - the middle click clipboard is managed at a lower level then GTK IIRC. – tobyodavies Sep 30 '11 at 05:05
  • The second `xsel` doesn't work either. Could it be because of my window manager? I'm using terminator under Xmoand in Debian. – nye17 Sep 30 '11 at 05:06
  • @tobyodavies I was aware of that, but Ctl-V doesn't work either, for both methods. Puzzling... – nye17 Sep 30 '11 at 05:08
  • I'd expect the GTK method not to work with terminator just cause I'm pretty sure that captures `ctrl+v` (there may well be a "paste" option in an edit menu though) – tobyodavies Sep 30 '11 at 05:10
  • You need the `-i` flag for xsel... try the new version - works for me – tobyodavies Sep 30 '11 at 05:12
  • @nye17 adding `-i` (or `-pi`) to xsel made it work for the middle click clipboard. The GTK one works with the `Ctrl+V` clipboard for me (on Ubuntu) – NullUserException Sep 30 '11 at 05:16
  • @tobyodavies ok, I tried all three, "middle-click", ctl-v, and the terminator-menu "paste". For the `clipboard` module, all three failed; for the `xsel -i` one, only the `middle-click` works. – nye17 Sep 30 '11 at 05:17
  • @nye17 that's expected - the `xsel -i` is only supposed to write to the middle-click clipboard, and the GTK version will only ever write to the `ctrl+c`/`ctrl+v` clipboard (which should be accessible through right-click/paste) – tobyodavies Sep 30 '11 at 05:23
  • @NullUserExceptionఠ_ఠ @tobyodavies Thanks guys! Now the terminator-menu `paste` works with `-b` and "middle-click" works with "-p". – nye17 Sep 30 '11 at 05:28
  • @nye17 I am glad you figured it out. It surprises me that terminator's `paste` works with `-b` though. – NullUserException Sep 30 '11 at 05:47
  • How about mentioning [PyGObject](https://github.com/sebp/PyGObject-Tutorial/blob/master/examples/clipboard_example.py) rather than PyGTK. [I've heard](http://stackoverflow.com/a/7130381/60075) that PyGTK is deprecated and PyGObject is the replacement. – Craig McQueen Aug 06 '14 at 00:37
  • I had the same problem with the GTK solution: in a script, it doesn't work, but on the Python console it does. I thought it had something to do with the program quitting too quickly after clipboard.store(), and I think I was right: if, in a script, after clipboard.store() you use raw_input() to get the user to hit a key before the program ends, then it works. It is kind of a hack, but for my purposes it was fine. – Fernando Jun 19 '18 at 08:00
17

As it was posted in another answer, if you want to solve that within python, you can use Pyperclip which has the added benefit of being cross-platform.

>>> import pyperclip
>>> pyperclip.copy('The text to be copied to the clipboard.')
>>> pyperclip.paste()
'The text to be copied to the clipboard.'
Community
  • 1
  • 1
Marcelo Lacerda
  • 847
  • 1
  • 15
  • 30
9

This is not really a Python question but a shell question. You already can send the output of a Python script (or any command) to the clipboard instead of standard out, by piping the output of the Python script into the xclip command.

myscript.py | xclip

If xclip is not already installed on your system (it isn't by default), this is how you get it:

sudo apt-get install xclip

If you wanted to do it directly from your Python script I guess you could shell out and run the xclip command using os.system() which is simple but deprecated. There are a number of ways to do this (see the subprocess module for the current official way). The command you'd want to execute is something like:

echo -n /path/goes/here | xclip

Bonus: Under Mac OS X, you can do the same thing by piping into pbcopy.

kindall
  • 178,883
  • 35
  • 278
  • 309
  • I prefer if the string specified by the script be sent to the clipboard, rather than all the output being piped to `xclip`, as the final output and the desired string are not necessarily the same. But you are right, I can use `subprocess` to send it to `xclip`, although I would prefer a slightly less "brute-force" way. – nye17 Sep 30 '11 at 05:13
  • doing it in python is nicer - allows the code to have more output than just a filename... – tobyodavies Sep 30 '11 at 05:15
  • Add a command-line flag to suppress everything but the pathname, then, or to optionally send it to standard error (so you can pipe it to `xclip` without catching the rest). You need a command-line flag anyway since you don't want to clobber the user's clipboard without being explicitly told to, so why not make it more unixy? – kindall Sep 30 '11 at 05:20
  • @kindall This time I wanna go for more pythonic ;-) – nye17 Sep 30 '11 at 05:32
  • A good reason not to use xclip: you don't control the shell environment necessarily. None of the cloud servers that I work on provide xsel or xclip, so a pure-python solution is much preferred. – Stabledog Jul 09 '15 at 17:41
  • How is this a shell question? `xclip` and `xsel` are certainly not shell built-ins, and they are implemented somewhere, somehow. It's a legitimate question to wonder how to implement their functionality in Python. – Clément Mar 07 '16 at 19:38
  • Well, one could always take a look at how the different GUI libraries for Python implemented clipboards, and write a compiled .so file for Python that does the same thing in any context. – Brōtsyorfuzthrāx Sep 16 '22 at 09:59
2

As others have pointed out this is not "Python and batteries" as it involves GUI operations. So It is platform dependent. If you are on windows you can use win32 Python Module and Access win32 clipboard operations. My suggestion though would be picking up one GUI toolkit (PyQT/PySide for QT, PyGTK for GTK+ or wxPython for wxWidgets). Then use the clipboard operations. If you don’t need the heavy weight things of toolkits then make your wrapper which will use win32 package on windows and whatever is available on other platform and switch accordingly!

For wxPython here are some helpful links:

http://www.wxpython.org/docs/api/wx.Clipboard-class.html

http://wiki.wxpython.org/ClipBoard

http://www.python-forum.org/pythonforum/viewtopic.php?f=1&t=25549

Stefano Mtangoo
  • 6,017
  • 6
  • 47
  • 93