xclip does not terminate when tracing it
XClip forks a child when launched without -verbose
. The only difference with -verbose
is that there is no child forked and the same original process handles ConvertSelection events.
Usually in X Window toolkits copy/paste is implemented via X Selections:
Selections are global server resources named by an atom and owned by a
particular client. The number of selections is not limited by the
protocol; as many selections as atoms may exist. Selections are
designed to provide the basis for building communication mechanisms
between clients. The official definition is found in the glosary of the
X Protocol:"...an indirect property with dynamic type; that is,
rather than having the property stored in the server, it is maintained
by some client (the ‘‘owner’’).
A selection is global in nature and is
thought of as belonging to the user (although maintained by clients),
rather than as being private to a particular window subhierarchy or a
particular set of clients."From the applications perspective,
selections provide a mechanism for transmitting information between X
clients. As X is a networking protocol, the existance of a separate
channel for data transmission between the various clients cannot be
assumed to exist. Selections are intended only for data transfer which
directly relates the the user-interface aspects of the application,
although there isn’t any enforcement of this policy.
Content of selection is stored in application itself and requested with
ConvertSelection event ("convert" here because there is a way for client
to ask for particular mimetype (or "view", or format) of selected data.
Conversion, again, happens in the application which owns selected buffer.
Because of this architecture, there is no way to "copy text to system
buffer and exit" - because you are a system buffer. XClip simulates "copy and exit"
by forking and daemonizing.
Avoid enter when pasting xsel / xclip
You could use tr, for example
date +%Y-%m-%d_%H:%M | tr -d '\n' | xclip -selection c
See this question for different ways to achieve it: Bash: Strip trailing linebreak from output
passthru hangs if the executed command writes to the clipboard
"xclip -i -selection clipboard > /dev/null"
should fix it
xclip doesn't close the STDOUT.
related to: this questions answer
Why `xclip .bashrc` takes much longer than system(xclip .bashrc) in ruby?
I doubt that xclip
just takes a long time to terminate when you use backticks to shell out. This has to do with the selection. Without any selection provided through -sel
it will default to XA_PRIMARY
which is conventionally used to implement copying and pasting via the middle mouse button.
When you run
$ xclip text.txt
the content becomes available through XA_PRIMARY
which means you can paste it through your middle mouse button or $ xclip -o
. It starts to get weird when you execute it thorugh a shell out in Ruby:
ruby -e '`xclip text.txt`
It never really terminates if you do nothing. It terminates when you select someting in your X11 system, for instance in the console or everywhere else. Just selection, marking something with your mouse. If you do not, it will hang and/or timeout at some point.
The same behavior can be observed when you use the verbose mode:
$ xclip -verbose text.txt
Connected to X server.
Using UTF8_STRING.
Reading text.txt...
Waiting for selection requests, Control-C to quit
Waiting for selection request number 1
The selection request, again, is served when you select something.
A good analysis tool for this is strace
(the -f
option is for tracking forks, too)
$ strace -f ruby -e '`xclip text.txt`'
...
poll([{fd=3, events=POLLIN|POLLOUT}], 1, 4294967295) = 1 ([{fd=3, revents=POLLOUT}])
writev(3, [{"\20\0\3\0\4\0\200\2INCR", 12}, {NULL, 0}, {"", 0}], 3) = 12
poll([{fd=3, events=POLLIN}], 1, 4294967295) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "\1\0\f\0\0\0\0\0\235\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 4096, 0, NULL, NULL) = 32
recvfrom(3, 0x165e964, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
recvfrom(3, 0x165e964, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=3, events=POLLIN}], 1, 4294967295
In the last line it hangs until a selection is made. poll()
is used to wait for a file event at the file descriptor. It will terminate at some point, but 4,294,967,295 ms is rather long. It can be traced the same with with just strace -f xclip text.txt
.
You can take a look at the file descriptors through ls -l /proc/PID/fd
. The one with number 3 is the file descriptor where xclip
waits for your selection.
What makes it so hard to debug is that if terminates instantly with strace xclip text.txt
, but not with strace -f text.txt
. The moment where you want to trace the fork it does not work anymore. That is the same problem you have with Ruby. It tries to trace the output, because Kernel#`
wants to return the output. This has probably also to do with the ticket #9 Not closing stdout when setting clipboard from stdin.
This is my theory. The moment you shell out and want to follow the output of xclip
, be it with Ruby to read from standard out, or strace
to trace the forks, the standard output does not get closed until you make a selection.
This does not explain it very well, but it demonstrates that is does not have to do anything with Ruby. I will create a question which focuses on xclip
only and not in the context of Ruby.
Git pre-push hook hangs after piping to xclip
xsel
, as well as xclip
, waits until another program explicitly fetches the selected data.
This behavior is a design-conditional of X11, since there "is no X selection buffer. The selection mechanism in X11 is an interclient communication mediated by the X server each time any program wishes to know the selection contents [...]. In order to implement modification of the selection(s) (in input, keep and exchange modes) [these programs detach] from the terminal, spawning a child process to supply the new selection(s) on demand. This child exits immediately when any other program takes over the selection(s)" -- from the xsel man-page
With other words your Gits pre-push
commit is executed until you start providing your text-selection to the clipboard. The process is then halted until you are making use of this text-snippet by invoking any command or executing any program which "fetches" the clipboard text.
Forking the xclip
-command does not work
My first idea was to detach this selection-providing process to let it live parallel to the (then) ongoing execution of your hook-script. Unfortunately this does not work, either the main-process ist halting anyways, until the subprocess returns, or the text-selection of the forked command is not available to the current X11-server.
Possible Solutions
Due to the behavior of the "clipboard" in X11 you must evade providing text-selections in the time-relevant processing of git-hooks.
Use a clipboard-manager - The most clipboard-managers (like Klipper [for KDE] or Glipper [for Gnome]) provide mechanisms to decouple the supply of data from its usage - which emulates the clipboard behavior of Windows and Mac OS.
Alias the
git-push
-command - if you're operating your git-repository mostly in the shell you might wrap thegit-push
-command in an alias or small shell-script which first invokes the push and afterwards provides the text-snippet to the clipboard. The disadvantage of this approach is, (besides of the cli-dependency) that the command will "hang" at the end, until you fetched the clipboard-content.
Unless you're not able to install additional software to your system i'd recommend the use of a clipboard-manager.
Use Klipper to put Text from the CLI into the X11-clipboard
You can access Klipper through the shell by using qdbus - a command-line-interface to Qt-applications. An example took from Milian Wolff's Blog Post, adapted to your script, may look like the following:
#!/bin/sh
PBI=\`git symbolic-ref --short HEAD\`
echo "**Backlog Item [$PBI]:**\n" > pr_messages/$PBI.md
git log develop..HEAD --format=" - [x] %B" >> pr_messages/$PBI.md
sed -r -i 's|\[([0-9]{4,})\]|[[\1](http://tracker/_workitems/\1)]|g' pr_messages/$PBI.md
PR_MESSAGE=$(cat pr_messages/$PBI.md)
qdbus org.kde.klipper /klipper setClipboardContents "$PR_MESSAGE"
Another interesting article about the interaction of qdbus and Klipper: https://askubuntu.com/questions/393601/a-command-for-pasting-the-same-as-ctrl-v
Related Topics
How to Find List of Odbc Drivers Installed on Linux
Extract Text Between Two Strings Repeatedly Using Sed or Awk
How to Redirect Output of Echo Over Ssh to a File
Initiating Dynamic Variables (Variable Variables) in Bash Shell Script
Installing Octave Package in Ubuntu
How to Find the Count of Multiple Words in a Text File
Linux/Module.H No Such File or Directory
How to Install an Older Version of PHP Using Apt-Get
How to Concatenate Files with the Same Prefix (And Many Prefixes)
Anaconda Libstdc++.So.6: Version 'Glibcxx_3.4.20' Not Found
Setting the Thread /Proc/Pid/Cmdline
Having Trouble Finding the Method _Kernel_Vsyscall Within the Linux Kernel
Arm Assembly "Retne" Instruction