Example Python code, that saves text to the Linux clipboard, persistently.

There are some quirks as to how the Linux X-server clipboard works, which have been observed for some time, but which will also affect how to write a Python script / program, that saves some text to the clipboard, but with the intention that the script should exit immediately, while the copied text should remain on the clipboard.

What works against that, is the way the X11 clipboard works generally, which is, that there is no part of the actual O/S, which stores the clipboard contents. Instead, the application being copied from stores this data, and the data is not transferred until another application, or the same application, pastes it again. This has as consequence, that if the first application tries to store the data to the clipboard but then exits, and if the second application next tries to paste it, the clipboard, by first approximation, will be empty because the first application, which was holding the data, has quit.

There may exist some Linux environments in which the desktop manager takes over in a case like that, to hold a copy of the data that was Copied, but my Debian / Stretch, Plasma 5.8 computer, which I name ‘Phosphene’, fails to do so. And this is also how or why, the Plasma 5 clipboard utility, which is named ‘Klipper’, will sometimes still show that last item at the top of its clipboard history, but why that item cannot be pasted (using <Ctrl>+V), until an earlier item is selected within Klipper, and then the item of interest is selected again, so that this most-recently copied item will actually be available on the clipboard again.

In principle, ‘Klipper’ has a setting which states ‘Assure clipboard never empty’. But, long story short, that setting does not work

(Update 4/09/2019, 6h05 : )

Actually, I have learned an intricacy, of how the Plasma 5, Klipper app interacts with the X11 clipboard, and which I was not aware of before. Apparently, the actual clipboard has 3 ‘slots’: ‘Primary’, ‘Secondary’, and ‘Clipboard’. Mouse-Highlighting will cause ‘Primary’ to point to the selected text, while <Ctrl>+C Copying will cause ‘Clipboard’ to point to the selected text. After that, middle-clicking with the mouse will Paste from ‘Primary’, while <Ctrl>+V will Paste from ‘Clipboard’.

When using <Ctrl>+C, an ideally Linux-compliant application will actually leave with both clipboard targets pointing at the selection, while certain applications such as Firefox will only end up with ‘Clipboard’ pointing at the selected text.

The only real pitfall in understanding ‘Klipper’ was, the fact that while it does keep a copy of the clipboard’s contents ‘on the side’, regardless of how they were Copied, Pasting that copy directly after the application Copied from has closed, is only facilitated for middle-clicking with the mouse, not for the <Ctrl>+V -type Pasting.

However, left-clicking on one of the entries in the Klipper History will cause the ‘Clipboard’ X11 pointer to point to it, unless that just happens to be the most-recent entry.

Basically, the user community wanted an alternative to Windows, that has familiar features, and instead, the Linux developers left them a well-hidden Easter Egg. (:1)


I recently needed to install a Python script, which hashes a domain-name, password combination, and which has as feature the ability to save the hash-code ‘to the clipboard’, instead of just printing it out, so that the user should next be able to paste the hash-code, and in some cases do so, without the hash-code ever being displayed. This script failed to work in its original version and I needed to modify it, to get it to work the way I wanted it to work.

(Updated 4/09/2019, 15h40 … )

(As of 4/08/2019 : )

The result was a Python script that does work, but which depends on an external package named ‘xsel’, actually to save the text to the clipboard. The way ‘xsel’ works by itself is, it forks into the background and keeps running, until some other process changes the clipboard contents, at which time ‘xsel’ exits. But then this also means that the ‘xsel’ process is holding on to that piece of text, for other applications to Paste, until this background process finally quits.

An added feature to the approach below is, the fact that ‘xsel’ has been instructed with the ‘-i’ flag to use its standard input as the source of text, so that, if the user next runs ‘ps fu -A‘, and sees the full list of running processes, the entry ‘xsel -i --clipboard‘ will be visible in the results, but the actual hash-code being held on the clipboard will not be visible.

Initially, I wanted to use ‘xclip’ instead, but a fact which I discovered was that, ‘xclip’ behaves differently when run in an interactive shell, from how it behaves when run in a batch shell. And, trying to correct this behaviour of ‘xclip’ wasted about 3 hours of my time. When run as part of a batch shell, ‘xclip’ just exits immediately, thereby defeating the purpose with which I was trying to use it.

The following is a snip of Python code, that finally did what it was supposed to do:


def console_main():
    import getpass, os
    if len(sys.argv) > 1:
        domain = sys.argv[1]
        domain = input("domain: ").strip()

    password = getpass.getpass("Password for %s: " % domain)
    generated = generate(password, domain)

    copied_to_clipboard = False

    if 'DISPLAY' in os.environ:
            import subprocess
            cmd = 'echo ' + generated + ' | tr -d \'\\n\''
            cmd = cmd + ' | xsel -i --clipboard'
            subprocess.check_call(cmd,  shell=True)
            copied_to_clipboard = True

    if copied_to_clipboard:
        sys.stdout.write("The password has been saved to the clipboard.\n")


So, to break it down, the Python script above has the text to be Copied to the clipboard in the string ‘generated’, and preceding code that stored the text in this string will not work, just from the example above. But the part of the code which I highlighted will copy the contents of ‘generated’ to the clipboard successfully…


The X11 clipboard allows one out of several targets to beĀ  selected, to Copy to, that are limited to ‘Primary’, ‘Secondary’, and ‘Clipboard’. If ‘xsel’ is left to copy the text to ‘Primary’, which is its default behaviour, then the text will appear in ‘Klipper’, but will not be available to be pasted, using <Ctrl>+V. Given my desktop manager, Copying the text to the target ‘Clipboard’ (from the script) assures, that it can be pasted again immediately using <Ctrl>+V, without ‘Klipper’ having to be involved.

But I don’t think for a moment, that this last detail would be a reason why professionally-written code fails to perform as designed.




A less-kludgy way to accomplish the same thing has been known for some time, which goes something like this:


import gtk

gtk.Clipboard().set_text("exciting clipboard contents")
gtk.Clipboard().set_can_store(None) # not sure if these last two lines are useful


While there is nothing wrong whatsoever with the code written here, this code did not work on my computer. And the reason seemed to be as follows: The function-call ‘gtk.Clipboard().store()‘ does in fact have as purpose, to signal to the O/S, that the present clipboard-contents should be saved ‘somewhere outside the present program, for use when this program has quit’. The problem with it is, if the desktop-manager’s faculty to do so is malfunctioning, trying to invoke it will not work any better than this existing / lacking faculty. On my computer named ‘Phosphene’, this seemed to be a lacking faculty.


Also, I just noticed that my initial Python code, failed to put a doubled backslash in front of the ‘n’, resulting in a cosmetic error which has since been corrected. But the code worked anyway because Bash has as peculiarity, that it’s perfectly legal to put a literal newline character, between two single-quotes, as delimiters. One can even do this from the command-line, and the result is that the single-quotes turn white-space interpretation off, so that the actual newline-character will form part of a single parameter.

One should not do it, but doing so resulted in code which nevertheless worked.

But, when we write a more-normal Bash script, we make the singly-quoted ‘\n’ a part of it, rather than making the ‘\n’ a literal newline character, that’s part of a singly-quoted Python string, that has (correct) escaped single-quotes inside it.



(Update 4/09/2019, 15h40 : )


I suppose that, to keep my criticism constructive, I should explain what the devs could have done better. I think it’s alright, that there is an extended functionality of the clipboard, which new users – or even more experienced users – may not be aware of.

But what I expect happened, is that the programmer behind the Klipper system-tray app, just assumed that it would be redundant, if the user could left-click on the most recent entry, and thereby have its content pointed to by the ‘Clipboard’ X11 selection, the same way it works for any other of the History entries.

But to the contrary, due to the complexity of the ways in which this clipboard works, to have this option would no longer be redundant. Instead, it would allow people who are only familiar with the Windows-style clipboard, to re-awaken text, which was Copied in an application that has been closed, and make that text available to be Pasted again.

As it stands, only ‘advanced’ users, who know about the unexpected effect of the middle mouse button, know how to accomplish this.


Yet, there is a way to configure the Plasma 5.8 Klipper system tray app, to accomplish the same thing. From the system tray, one can right-click on Klipper, left-click on “Configure Clipboard”, and then, within the “General” Tab, Un-check “Text Selection Only”, and Check “Synchronize contents of the clipboard and the selection”. Then, click “Apply”. In my experience, this actually syncs the ‘Primary’ and the ‘Clipboard’ X11 selections, so that both uses of the clipboard will benefit from whatever extent, to which the desktop preserves the content of either, after an application is closed.



Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>