在Node.js中复制到剪贴板?

154

是否有办法在Node.js中复制到剪贴板?有没有任何模块或想法?我正在一个桌面应用程序中使用Node.js。希望这样可以解释为什么我想要能够实现这个。

11个回答

163

对于 OS X:

function pbcopy(data) {
    var proc = require('child_process').spawn('pbcopy'); 
    proc.stdin.write(data); proc.stdin.end();
}

write() 函数可以接受缓冲区或字符串。字符串的默认编码为 utf-8。


5
在 REPL 中进行快速数据转换非常有用。 - William
4
这仅适用于Mac OS。 - Kenneth
好的,现在的目标是将这个保存为一个VSCode代码片段! - undefined

125

请查看clipboardy。它可以让您在跨平台上复制/粘贴。它比另一个答案中提到的copy-paste模块更加活跃地维护,并且解决了该模块的许多问题。

const clipboardy = require('clipboardy');

// Copy
clipboardy.writeSync('');

// Paste
clipboardy.readSync();
//

2
它比“复制粘贴”模块更好,因为它也支持双字节字符。但是在Windows 32位操作系统上存在问题。 - Ponmudi VN
3
Windows 32位支持已经修复:https://github.com/sindresorhus/clipboardy/commit/3be3ee6b9b9cd736623fcc8ebb1aa9e0c42371b4 - Sindre Sorhus
我在 Cypress 中运行了 npm install clipboardy。我有一个按钮在我的网络应用程序中,点击该按钮应该获取剪贴板内容,但它返回 undefined。如有任何建议,请提供。https://dev59.com/P1IH5IYBdhLWcg3wBn7F - soccerway
@Miquel 包已完全维护。实际上,你的问题是你的项目不是一个适当的 ES 模块项目。 - Sindre Sorhus
@SindreSorhus 我已经删除了评论,上次我看到旧的评论是在2022年(比copy-paste最后一个评论更早)。无论如何,这个库与所有项目配置不完全兼容,我正在一个使用node.js和typescript的项目上工作,其中所有的库都能正常工作,只有这个库不能。我发现Xavi的npm i copy-paste在第一次安装时没有任何兼容性问题,非常好用。如果这个库能够在任何项目中都没有问题,无论它是否被良好配置(从库开发者的角度来看),那将是很棒的。 - Miquel

39

这里有一个提供copypaste功能的模块:https://github.com/xavi-/node-copy-paste

当执行require("copy-paste").global()命令时,将添加两个全局函数:

> copy("hello") // Asynchronously adds "hello" to clipbroad
> Copy complete
> paste() // Synchronously returns clipboard contents
'hello'

和其他答案提到的一样,要在 Node 中复制和粘贴,您需要调用外部程序。在 node-copy-paste 的情况下,它会调用 pbcopy/pbpaste(适用于 OSX)、xclip(适用于 Linux)和 clip(适用于 Windows)。

当我在一个副业项目的 REPL(交互式命令行界面)中做很多工作时,这个模块非常有帮助。不用说,copy-paste 只是一个命令行实用程序 -- 它 不适用于 服务器工作。


2
这是最好的答案。它跨平台,而且运行得非常顺畅。 - gilly3
4
也许你需要加上“这是你自己的代码”这句话,以符合 Stack Overflow 的政策。 - towc

37

在Windows中最短的方法:

const util = require('util');
require('child_process').spawn('clip').stdin.end(util.inspect('content_for_the_clipboard'));

1
需要先 require util 才能运行!谢谢…… - LIXer
9
谢谢!不需要使用“util”依赖项,可以按如下方式正常工作:require('child_process').spawn('clip').stdin.end("content_for_the_clipboard"); - darmis
我在没有首先包含 const util = require("util") 的情况下收到了 ReferenceError: util is not defined 错误。 我在Electon的主进程和渲染进程中都进行了测试,但没有成功。 话虽如此,从node 12.14.1 CLI中测试是可以的。 基于用例,我认为最好定义util以确保安全。 - Benargee
5
几乎可以运行:它会复制带有单引号的字符串。有人知道如何防止这种行为吗? - m4cbeth
5
@m4cbeth,去掉“util.inspect”,不要使用单引号。require('child_process').spawn('clip').stdin.end('content_for_the_clipboard'); - Eric Bynum

25
剪贴板不是操作系统固有的功能,而是取决于所运行操作系统的窗口系统。例如,如果你想在X环境下实现剪贴板功能,你需要使用与Xlib和/或XCB相关的库。Node.js已经提供了Xlib的绑定,可以通过https://github.com/mixu/nwm访问。不过我不确定它是否可以让你访问X剪贴板,你可能需要自己编写代码来实现。对于Windows环境,你需要单独的绑定库。
编辑:如果你想要采用一些奇怪的方法,你也可以使用xclip。
var exec = require('child_process').exec;

var getClipboard = function(func) {
  exec('/usr/bin/xclip -o -selection clipboard', function(err, stdout, stderr) {
    if (err || stderr) return func(err || new Error(stderr));
    func(null, stdout);
  });
};

getClipboard(function(err, text) {
  if (err) throw err;
  console.log(text);
});

1
有一个类似于copy()的铬版本将会很棒。 - user7090116

4

Mac操作系统有一个本地命令行pbcopy,可以用于此用例:

require('child_process').exec(
    'echo "test foo bar" | pbcopy',

    function(err, stdout, stderr) {
        console.log(stdout); // to confirm the application has been run
    }
);

在Linux中使用相同的代码,但将pbcopy替换为Xclipapt get install xclip)。


有趣!你觉得在Windows上也有一种方法来做这个吗?那么,将xclip捆绑到我的程序中呢?因为我不想要求用户安装xclip。 - Tower
1
我发现在Windows中有这样的东西:echo fooo | clip。那么,在Linux中如何做到不要求用户安装任何东西呢? - Tower
1
“echo fooo | clip” 可以工作,但结果会在原始字符串的末尾包含一个 ‘\n’,这超出了我的预期。 - LIXer
如果字符串包含像“福星高照”这样的非英文字符,那么这种方法将无法正常工作。 - Aero Wang

3

我通过创建一个处理此问题的不同应用程序来实现这一点。虽然这并不是最好的方法,但它能够起作用。

我使用 Windows 并创建了一个 VB.NET 应用程序:

Module Module1

    Sub Main()
        Dim text = My.Application.CommandLineArgs(0)
        My.Computer.Clipboard.SetText(text)
        Console.Write(text) ' will appear on stdout
    End Sub
End Module

接下来在 Node.js 中,我使用child_process.exec 运行 VB.NET 应用程序,并将要复制的数据作为命令行参数传递:

require('child_process').exec(
    "CopyToClipboard.exe \"test foo bar\"",

    function(err, stdout, stderr) {
        console.log(stdout); // to confirm the application has been run
    }
);

你觉得你能直接在命令行中完成这个吗?写一个应用程序意味着我需要为Mac、Linux和Windows编译它。 - Tower
@rFactor:很抱歉,我对Mac/Linux没有任何经验,并且我不知道是否有内置的剪贴板命令。 - pimvdb
我使用命令 'echo "test foo bar" | clip',它有效。但结果有一个换行符 \n,它破坏了我的工作... - LIXer

3

我发现没有一个解决方案适用于Windows,也没有明显的地方可行,因此重新发布了这个,在Google搜索的第2页深处找到,使用Windows本地命令行clip,并避免任何可能凌乱的命令行解决方法,如建议中的echo foo | clip

  var cp = require("child_process");
  var child = cp.spawn('clip');
  child.stdin.write(result.join("\n"));
  child.stdin.end();

希望这能帮到某些人!

1
如果您想将文件(而不是其内容)复制到剪贴板,请考虑以下方法:
对于macOS:
let filePath; // absolute path of the file you'd like to copy

require('child_process').exec(  
  `osascript -e 'set the clipboard to POSIX file "${filePath}"'`,

  function (err, stdout, stderr) {
    console.log(stdout); // to confirm the application has been run
  }
);

For Windows:

const filePath; // absolute path of the file you'd like to copy

// Make a temporary folder
const tmpFolder = path.join(__dirname, `tmp-${Date.now()}`);
fs.mkdirSync(tmpFolder, { recursive: true });

// Copy the file into the temporary folder
const tmpFilePath = path.join(tmpFolder, path.basename(filePath));
fs.copyFileSync(filePath, tmpFilePath);

// To copy the contents of the folder in PowerShell,
// you need to add a wildcard to the end of the path
const powershellFolder = path.join(tmpFolder, '*');

require('child_process').exec(
  `Set-Clipboard -PATH "${powershellFolder}"`, { 'shell': 'powershell.exe' },

  function (err, stdout, stderr) {
    console.log(stdout); // to confirm the application has been run
  }
);

0

以下是在 Windows 上使用 node-ffi 实现的方法,它可以直接与 Windows 原生剪贴板 API 进行交互。(这意味着您还可以读取/写入不同的剪贴板格式)

var {
  winapi,
  user32,
  kernel32,
  constants
} = require('@kreijstal/winffiapi')
const GMEM_MOVEABLE=0x2;
var stringbuffer=Buffer.from("hello world"+'\0');//You need a null terminating string because C api.
var hmem=kernel32.GlobalAlloc(GMEM_MOVEABLE,stringbuffer.length);
var lptstr = kernel32.GlobalLock(hmem);
stringbuffer.copy(winapi.ref.reinterpret(lptstr, stringbuffer.length));
kernel32.GlobalUnlock(hmem);
if (!user32.OpenClipboard(0)){
    kernel32.GlobalLock(hmem);
    kernel32.GlobalFree(hmem);
    kernel32.GlobalUnlock(hmem);
    throw new Error("couldn't open clipboard");
}
user32.EmptyClipboard();
user32.SetClipboardData(constants.clipboardFormats.CF_TEXT, hmem);
user32.CloseClipboard();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接