48

I'd like my python program to place some text in the Mac clipboard.

Is this possible?

David Sykes
  • 48,469
  • 17
  • 71
  • 80

7 Answers7

109

How to write a Unicode string to the Mac clipboard:

import subprocess

def write_to_clipboard(output):
    process = subprocess.Popen(
        'pbcopy', env={'LANG': 'en_US.UTF-8'}, stdin=subprocess.PIPE)
    process.communicate(output.encode('utf-8'))

How to read a Unicode string from the Mac clipboard:

import subprocess

def read_from_clipboard():
    return subprocess.check_output(
        'pbpaste', env={'LANG': 'en_US.UTF-8'}).decode('utf-8')

Works on both Python 2.7 and Python 3.4.

2021 Update: If you need to be able to read the clipboard on other operating systems and not just Mac and are okay with adding an external library, pyperclip also seems to work well. I tested it on Mac with Unicode text:

python -m pip install pyperclip
python -c 'import pyperclip; pyperclip.copy("私はDavid!")'  # copy
python -c 'import pyperclip; print(repr(pyperclip.paste()))'  # paste
David Foster
  • 6,931
  • 4
  • 41
  • 42
  • 2
    i have no idea why this one gets so little love, it's by far the most elegant and reliable method on this page – hyperknot Mar 02 '15 at 01:14
  • 1
    Why thank you. I needed to write this function to push Japanese text through the clipboard, so I had to make it work with Unicode. – David Foster Mar 03 '15 at 01:35
  • Excellent. Very useful in a utility function for cleaning up extracts from JSTOR pdf files; thanks. – cphlewis Apr 19 '15 at 06:03
  • WAY better and more reliable than Tkinter. Thank you. – Lincoln Bergeson Jul 13 '17 at 16:23
  • 1
    Great solution. No need for external libraries. Thanks. – Farid Feb 26 '21 at 05:43
  • @DavidFoster I’m using pyperclip now and it seems to be conflicting with pyautogui. Throws an Attribute Error regarding the pasteboard. Have you ever run into this issue? Seems like for me your first answer is the best at this point. Here’s my post on github: https://github.com/asweigart/pyperclip/issues/208 – Jason Aug 02 '21 at 01:38
21

A simple way:

cmd = 'echo %s | tr -d "\n" | pbcopy' % str
os.system(cmd)

A cross-platform way:
https://stackoverflow.com/a/4203897/805627

from Tkinter import Tk
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append('i can has clipboardz?')
r.destroy()
Community
  • 1
  • 1
user805627
  • 4,247
  • 6
  • 32
  • 43
  • 1
    Code block #1 probably does not work if the text to be written to the clipboard contains Unicode or shell characters like | or &. Code block #2 creates an extra dock icon on OS X. I've provided my own answer to this question which doesn't have these issues. – David Foster Mar 03 '15 at 01:42
  • Too bad that the cross-platform way ... doesn't work reliably. And that you also missed the `r.update()` call that the original answer shows now. – GhostCat Aug 30 '19 at 06:23
19

The following code use PyObjC (https://pyobjc.readthedocs.io)

from AppKit import NSPasteboard, NSArray

pb = NSPasteboard.generalPasteboard()
pb.clearContents()
a = NSArray.arrayWithObject_("hello world")
pb.writeObjects_(a)

As explained in Cocoa documentation, copying requires three step :

  • get the pasteboard
  • clear it
  • fill it

You fill the pasteboard with an array of object (here a contains only one string).

FabienAndre
  • 4,514
  • 25
  • 38
8

New answer:

This page suggests:

Implementation for All Mac OS X Versions

The other Mac module (MacSharedClipboard.py, in Listing 4) implements the clipboard interface on top of two command-line programs called pbcopy (which copies text into the clipboard) and pbpaste (which pastes whatever text is in the clipboard). The prefix "pb" stands for "pasteboard," the Mac term for clipboard.

Old answer:

Apparently so:

http://code.activestate.com/recipes/410615/

is a simple script demonstrating how to do it.

Edit: Just realised this relies on Carbon, so might not be ideal... depends a bit what you're using it for.

Community
  • 1
  • 1
mavnn
  • 9,101
  • 4
  • 34
  • 52
6

I know this is an older post, but I have found a very elegant solution to this problem.

There is a library named PyClip, which can be found at https://github.com/georgefs/pyclip-copycat.

The syntax is pretty simple (example from the Github repo):

import clipboard

# copy some text to the clipboard
clipboard.copy('blah blah blah')

# get the text currently held in the clipboard
text = clipboard.paste()

once you've passed clipboard.copy('foo') you can just cmd + v to get the text

AtomicBen
  • 75
  • 1
  • 5
  • I miss explaining the advantage of `clipboard` to [`pyperclip`](https://stackoverflow.com/a/25802742/1705829) - see example here - which is needed by clipboard. – Timo May 03 '22 at 20:35
1

if you just wanted to put text into the mac clipboard, you could use the shell's pbcopy command.

jellyfishtree
  • 1,811
  • 1
  • 10
  • 11
  • 1
    If it's a super-short python command, you can pipe the command's output to pbcopy like this: python -c "print 'hi'" | pbcopy. You can also include a bunch of consecutive commands: python -c 'import time,sys; sys.stdout.write(str(int(time.time())))' | pbcopy. This one copies the unix time without the trailing newline to the clipboard. – Ariel Cabib May 19 '15 at 13:20
0

Based on @David Foster's answer, I implemented a simple script(only works for mac) to decode python dict(actually, it is parsed from a JSON string) to JSON string, because sometimes when debugging, I need to find the mistake(s) in the data(and the data body is very big and complex, which is hard for human to read), then I would paste it in python shell and json.dumps(data) and copy to VS code, prettify the JSON. So, the script below would be very helpful to my works.

alias pyjson_decode_stdout='python3 -c "import sys, json, subprocess; \
    print(json.dumps(eval(subprocess.check_output( \
        \"pbpaste\", env={\"LANG\": \"en_US.UTF-8\"}).decode(\"utf-8\"))))"'
alias pyjson_decode='python3 -c "import json, subprocess; \
    output=json.dumps(eval(subprocess.check_output(\
        \"pbpaste\", env={\"LANG\": \"en_US.UTF-8\"}).decode(\"utf-8\"))).encode(\"utf-8\"); \
    process=subprocess.Popen(\"pbcopy\", env={\"LANG\": \"en_US.UTF-8\"}, stdin=subprocess.PIPE); \
    process.communicate(output)"'

add the script to ~/.zshrc or ~/.bashrc (based on which sh you use) and new a terminal window, the example usage is copy one dict data, e.g. {'a': 1} and enter pyjson_decode_stdout would print the parsed json based on this dict; Copy and enter pyjson_decode would write this string to pbcopy.

d0zingcat
  • 929
  • 8
  • 10