wl-copy seems to be mishandling `stderr`
Seems like wl-copy is doing something wrong with stderr/logging handling.
I am trying to write a clipboard anonymization script that should go like:
notify-send --expire-time=3000 "kdn-anonymize-clipboard" "$( { wl-paste | kdn-anonymize | wl-copy ; } 2>&1 )"
Initially I thought I don't understand bash process substitution and/or redirection, but after a few attempts of solving it over the months I pinned it down to wl-copy mishandling stderr in some way.
Basically above snippet results in the script hanging up indefinitely unless I augment the wl-copy call with 2>/dev/null (or any other file like 2>/tmp/wl-copy.stderr).
For minimal reproducible examples, this is working:
bash -c 'val="$( { cat -n ; echo "test stderr" >&2; } 2>&1 < <(echo "test input") > >( wl-copy 2>/tmp/wl-copy.stderr ) )"; printf "val=%s\n" "$val"'
while this is not:
bash -c 'val="$( { cat -n ; echo "test stderr" >&2; } 2>&1 < <(echo "test input") > >( wl-copy ) )"; printf "val=%s\n" "$val"'
This might be related to following:
- https://github.com/bugaevc/wl-clipboard/issues/201
- https://github.com/bugaevc/wl-clipboard/issues/212
- https://github.com/bugaevc/wl-clipboard/pull/209
Hi!
Initially I thought I don't understand bash process substitution and/or redirection, but after a few attempts of solving it over the months I pinned it down to wl-copy mishandling stderr in some way.
Perhaps you could clarify what you mean by "mishandling" in this context?
You're probably unhappy about the forked instance of wl-copy keeping stderr instead of closing it.
$( { wl-paste | kdn-anonymize | wl-copy ; } 2>&1 )Basically above snippet results in the script hanging up indefinitely
Well, yes, if you pass the stdout pipe as stderr too (which is what 2>&1 does) and then wait for all the copies of writing end of the pipe to be closed (which is what $(...) does), you're going to have to wait until the background wl-copy exits. So don't do that if you don't intend to wait for that. Why would you want the stderr of wl-copy to appear in notify-send's argv anyway?
You're probably unhappy about the forked instance of
wl-copykeeping stderr instead of closing it.
Your explanation makes sense. I would expect:
- [x]
wl-pasteto exit closing it's FDs - [x]
kdn-anonymizeseesstdinclosed, so it closes it'sstdout(wl-copy'sstdin) - [ ]
wl-copyseesstdinclosed, cleans up it's FDs and exits.
Is there a particular reason why stderr is kept open?
Why would you want the stderr of wl-copy to appear in notify-send's argv anyway?
- I basically didn't think (nor now want) to treat
wl-pasteany different way than the rest of the pipeline. - To for example observe messages like https://github.com/bugaevc/wl-clipboard/issues/201 when I misconfigure something else.
wl-copyseesstdinclosed, cleans up it's FDs and exits.Is there a particular reason why
stderris kept open?
We keep stderr open to be able to report errors, if any. Though it's possible that I will change my mind about this, given the never-ending torrent of issues that people file about it :slightly_smiling_face:
wl-copy doesn't fully exit once its stdin is closed. If it did, you would be unable to paste. It needs to stay alive to service paste requests. You may want to explicitly run wl-copy --foreground for clarity.
wl-copydoesn't fully exit once its stdin is closed. If it did, you would be unable to paste. It needs to stay alive to service paste requests. You may want to explicitly runwl-copy --foregroundfor clarity.
oh, I was under the impression the clipboard is stored in a system session or something like that instead of within wl-copy memory
Why does the process need to stick around after stdin gets closed & the child process is joined(?)? This is perhaps naive, but could it use a file in /tmp or something instead?
wl-copydoesn't fully exit once its stdin is closed. If it did, you would be unable to paste. It needs to stay alive to service paste requests. You may want to explicitly runwl-copy --foregroundfor clarity.
So I wondered if it was the forking, which eventually led me here.
I was trying to get write a simple kakoune wl-copy integration: https://stackoverflow.com/questions/41396835/how-do-i-yank-to-system-clipboard-in-kakoune
When I saw this answer, I was like "what in the world why is the wl-copy example so much more complicated, who cares about stdout/stderr and forking":
hook global RegisterModified '"' %{ nop %sh{
case $(uname) in
Linux)
wl-copy -n "$kak_main_reg_dquote" > /dev/null 2>&1 & ;;
Darwin)
printf "%s" "$kak_main_reg_dquote" | pbcopy ;;
esac
}}
After trial and error, I believe this should be the correct line:
wl-copy --foreground -- "$kak_main_reg_dquote"
however, adding --foreground actually makes things worse. If I add --foreground (even if I redirect stdout and stderr to /dev/null and set stdin to /dev/null) wl-copy never exits.
This seems to be the correct incantation:
wl-copy -- "$kak_main_reg_dquote" 2> /dev/null
... this is excessively weird. Please don't keep this behavior. If there's no possibility of further input (i.e., stdin is a closed pipe or a non-pipe file descriptor that has hit EOF, or was never provided) ... I do not see why wl-copy should ever hang around.