简体   繁体   English

如何通过Node.js中的child_process.spawn()将长字符串传递给/ dev / stdin?

[英]How do you pipe a long string to /dev/stdin via child_process.spawn() in Node.js?

I'm trying to execute Inkscape by passing data via stdin . 我试图通过stdin传递数据来执行Inkscape。 Inkscape only supports this via /dev/stdin . Inkscape仅通过/dev/stdin支持此功能。 Basically, I'm trying to do something like this: 基本上,我正在尝试做这样的事情:

echo "<sgv>...</svg>" | inkscape -z -f /dev/stdin -A /dev/stdout

I don't want to have to write the SVG to disk. 我不想将SVG写入磁盘。

I tried just using stdin.write() , but it doesn't work (maybe because of /dev/stdin ): 我尝试使用stdin.write() ,但它不起作用(可能是因为/dev/stdin ):

var cmd = spawn("inkscape", ["-z", "-f", "/dev/stdin", "-A", "/dev/stdout"], {encoding: "buffer", stdio: ["pipe", stdoutPipe, "pipe"]});

cmd.stdin.write(svg);

This does work, but I have to write the SVG to disk: 这确实有效,但我必须将SVG写入磁盘:

var cmd = spawn("inkscape", ["-z", "-f", "/dev/stdin", "-A", "/dev/stdout"], {encoding: "buffer", stdio: [fs.openSync('file.svg', "a"), stdoutPipe, "pipe"]});

I tried passing a stream to stdio , but I just keep getting TypeError: Incorrect value for stdio stream: [object Object] 我尝试将流传stdio ,但我只是继续获取TypeError: Incorrect value for stdio stream: [object Object]

Any ideas? 有任何想法吗?

Addendum 附录

The examples use Inkscape, but my question applies to any arbitrary program using /dev/stdin . 这些示例使用Inkscape,但我的问题适用于使用/dev/stdin任意程序。

By the way, this would work for me: 顺便说一句,这对我有用:

var exec = require('child_process').exec;
exec("echo \"<svg>...</svg>\" | inkscape -z -f /dev/stdin -A /dev/stdout | cat", function (error, stdout, stderr) {});

Except, my SVG is too long, so it throws an error: Error: spawn Unknown system errno 7 除了,我的SVG太长,所以它抛出一个错误: Error: spawn Unknown system errno 7

Alright, I don't have Inkscape, but this appears to solve the Node.js side of things. 好吧,我没有Inkscape,但这似乎解决了Node.js方面的问题。 I'm using wc as a stand in Inkscape; 我正在使用wc作为Inkscape的支架; the -c option simply outputs the number of bytes in a given file (in this case /dev/stdin ). -c选项只输出给定文件中的字节数(在本例中为/dev/stdin )。

var child_process = require('child_process');

/**
 * Create the child process, with output piped to the script's stdout
 */
var wc = child_process.spawn('wc', ['-c', '/dev/stdin']);
wc.stdout.pipe(process.stdout);

/**
 * Write some data to stdin, and then use stream.end() to signal that we're
 * done writing data.
 */
wc.stdin.write('test');
wc.stdin.end();

The trick seems to be signaling that you're done writing to the stream. 这个技巧似乎表明你已经完成了对流的写作。 Depending on how large your SVG is, you may need to pay attention to backpressure from Inkscape by handling the 'drain' event. 根据SVG的大小,您可能需要通过处理'drain'事件来关注 Inkscape的背压


As for passing a stream into the child_process.spawn call, you instead need to use the 'pipe' option, and then pipe a readable stream into child.stdin , as shown below. 至于将流传child_process.spawn调用,您需要使用'pipe'选项,然后将可读流传child.stdin ,如下所示。 I know this works in Node v0.10.26, but not sure about before that. 我知道这在Node v0.10.26中有效,但在此之前不确定。

var stream = require('stream');
var child_process = require('child_process');

/**
 * Create the child process, with output piped to the script's stdout
 */
var wc = child_process.spawn('wc', ['-c', '/dev/stdin'], {stdin: 'pipe'});
wc.stdout.pipe(process.stdout);

/**
 * Build a readable stream with some data pushed into it.
 */
var readable = new stream.Readable();
readable._read = function noop() {}; // See note below
readable.push('test me!');
readable.push(null);

/**
 * Pipe our readable stream into wc's standard input.
 */
readable.pipe(wc.stdin);

Obviously, this method is a bit more complicated, and you should use the method above unless you have good reason to (you're effectively implementing your own readable string). 显然,这种方法有点复杂,你应该使用上面的方法,除非你有充分的理由(你有效地实现了自己的可读字符串)。

Note: The readable._push function must be implemented according to the docs , but it doesn't necessarily have to do anything. 注意:必须根据文档实现readable._push函数,但它不一定要做任何事情。

So, I figured out a work around. 所以,我想出了一个解决方案。 This seems like a bit of a hack, but it works just fine. 这看起来有点像黑客,但它的工作正常。

First, I made this one line shell script: 首先,我制作了这个单行shell脚本:

cat | inkscape -z -f /dev/stdin -A /dev/stdout | cat

Then, I simply spawn that file and write to the stdin like this: 然后,我只是生成该文件并写入stdin,如下所示:

cmd = spawn("shell_script");

cmd.stdin.write(svg);
cmd.stdin.end();
cmd.stdout.pipe(pipe);

I really think this should work without the shell script, but it won't (for me at least). 我真的认为这应该没有shell脚本,但它不会(至少对我来说)。 This may be a Node.js bug. 这可能是Node.js错误。

The problem comes from the fact that file descriptors in node are sockets and that linux (and probably most Unices) won't let you open /dev/stdin if it's a socket. 问题来自于节点中的文件描述符是套接字,并且如果它是套接字,那么linux(可能是大多数Unices)将不允许你打开/ dev / stdin。

I found this explanation by bnoordhuis on https://github.com/nodejs/node-v0.x-archive/issues/3530#issuecomment-6561239 我在https://github.com/nodejs/node-v0.x-archive/issues/3530#issuecomment-6561239上找到了bnoordhuis的解释

The given solution is close to @nmrugg's answer : 给定的解决方案接近@nmrugg的答案:

var run = spawn("sh", ["-c", "cat | your_command_using_dev_stdin"]);

After further work, you can now use the https://www.npmjs.com/package/posix-pipe module to make sure that the process sees a stdin that is not a socket. 进一步的工作之后,您现在可以使用https://www.npmjs.com/package/posix-pipe模块来确保进程看到的stdin不是套接字。

look at the 'should pass data to child process' test in this module which boils down to 看看这个模块中的“应该将数据传递给子进程”测试归结为

var p = pipe()
var proc = spawn('your_command_using_dev_stdin', [ .. '/dev/stdin' .. ],
    { stdio: [ p[0], 'pipe', 'pipe' ] })
p[0].destroy() // important to avoid reading race condition between parent/child
proc.stdout.pipe(destination)
source.pipe(p[1])

正如Inkscape错误171016所示,Inkscape不支持通过stdin导入,但它在他们的愿望清单上。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Node.js中通过child_process.spawn()将长字符串传递给? - How do i pipe a long string to via child_process.spawn() in Node.js? Node.js:捕获`child_process.spawn`的STDOUT - Node.js: Capture STDOUT of `child_process.spawn` node.js child_process.spawn no stdout除非&#39;inherit&#39; - node.js child_process.spawn no stdout unless 'inherit' 如何在node.js中清除child_process.spawn()上的子进程 - How to clean child processes on child_process.spawn() in node.js 如何在Ubuntu中作为命令或服务运行可执行文件(使用Node.js child_process.spawn())? - How to run executable file in Ubuntu as a command or service (with Node.js child_process.spawn())? 如何在Windows上正确使用node.js child_process.spawn()重定向? - How to correctly use node.js child_process.spawn() redirection on Windows? 如何确保node.js child_process.spawn将错误消息写入控制台 - How to ensure node.js child_process.spawn will write error messages to the console 如何通过child_process.spawn()执行本地安装的Node.js应用程序? - How to execute locally installed Node.js application by child_process.spawn()? node.js - 如何调整 child_process.spawn() 的标准输出缓冲区大小(又名 highWaterMark)? - node.js - How to adjust the the stdout buffer size (aka highWaterMark) of child_process.spawn()? 如何使用Node的child_process.spawn将文件作为输入? - How do you use a file as input with Node's child_process.spawn?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM