I've got a script which calls to xclip
inside. Something like this:
#!/bin/bash
RESULT="some data"
echo $RESULT | xclip
echo $RESULT
xclip
puts puts the data from its stdin to the clipboard, spawns a background thread to preserve that buffer (that's how clipboard works in X11) and detaches it from tty.
If I run a script directly, it works as expected:
$ ./script.sh
some data
$
However, if I'll try to pass it's output into a pipeline, it hangs until xclip
background process ends (basically, until someone else puts data into the clipboard).
$ ./script.sh | ./another_script.sh # it hangs
I found that xclip
has a -f
flag which seem to fix that problem.
From the man page:
when xclip is invoked in the in mode with output level set to silent (the defaults), the filter option will cause xclip to print the text piped to standard in back to standard out unmodified
However, I'm trying to understand why does it work that way.
I've created another example which behaves the same way:
echo $(sleep 5 &)
Also, I've been told that in fish
my example works without -f
flag.
So, the question is:
1. Is this a bug of a shell (bash
and zsh
) or an expected behaviour?
2. How does -f
flag affects that behaviour? From the man page, it does not seems very related.
3. How to make other scripts (e.g. sleep
) work the way xclip
works with -f
flag?
By default,
Combining the above, when you execute
/script.sh | ./another_script.sh
, the backgroundedxclip
will inherit the 'script.sh' stdout (which is the input to./another_script.sh
), at this time, there are two processes (script.sh, xclip) which are connected to the pipe. Only when both will close STDOUT (or will terminate), the./another_script.sh
will see the EOF on the pipe, and will be able to exit (assuming it's waiting for EOF on input).The solution for those cases is for the back-grounded process to close stdout, therefore allowing pipelines to complete. Usually, the stdout will be redirected to stderr, if output is needed. Most likely, the '-f' closes the STDOUT.
Per man
xclip
, possible to writeecho $RESULT | xclip -f
(no need for extra echo) to avoid the problem, and allow script to run as part of a pipelineman
fork
and manpipe
provides the details. In particularman 2 fork:
man 7 pipe: