2

I'm trying to use child_process to execute xclip -selection c, but it seems to hang or significantly delay execution.

I've tried using execSync,

require('child_process').execSync('echo hi | xclip -selection c') && console.log('done');

I've also tried using exec,

require('child_process').exec('echo hi | xclip -selection c', (a) => console.log('done', a)) && undefined;

In both cases, there is a noticeable delay between pressing enter and when done is printed. However, the clipboard is actually affected almost immediately, it seems node just doesn't seem to realize the command is complete.

Also to note, the delay seems to vary between executions. Plus, the exec variant seems to delay for less time than the execSync variant which sometimes seems to hang indefinitely.

junvar
  • 11,151
  • 2
  • 30
  • 46

2 Answers2

4

Apologies for answering my own question, but I stumbled upon the answer shortly after posting the question.

Apparently xclip, by default, doesn't terminate when invoked, but keeps listening for more input. To instruct xclip to only expect 1 input requires the -l argument, e.g.:

require('child_process').execSync('echo hi | xclip -selection c -l') && console.log('done');

source: https://github.com/astrand/xclip/issues/45

junvar
  • 11,151
  • 2
  • 30
  • 46
0

Since the clipboard is an active protocol there needs to be a process that answers the requests from the X11 server. When you close xclip you lose the clipboard. So xclip needs to be running in the background. Node won't close as long as it has subprocesses that it owns. You must disown them and also you need to close all the streams connecting the node process with them. That being said here is the snippet to do it.


const child_process = require('child_process');
const xclip = child_process.spawn('xclip', ['-se', 'c'], { detached: true, stdio: ['pipe', 'ignore', 'ignore'] });
xclip.stdin.end('copy this');
xclip.unref();

The process is unref, stdin is ended, and stdout and seterr are ignored.