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

我试图通过stdin传递数据来执行Inkscape。 Inkscape只通过/dev/stdin 。 基本上,我试图做这样的事情:

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

我不想将SVG写入磁盘。

我尝试使用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); 

这确实有用,但是我必须将SVG写入磁盘:

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

我试图传递一个stream到stdio ,但我只是不断得到TypeError: Incorrect value for stdio stream: [object Object]

有任何想法吗?

附录

这个例子使用Inkscape,但是我的问题适用于任何使用/dev/stdin任意程序。

顺便说一下,这对我来说很有用:

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

除此之外,我的SVG太长了,所以会抛出一个错误: Error: spawn Unknown system errno 7

好吧,我没有Inkscape,但这似乎解决了Node.js方面的事情。 我使用wc作为Inkscape的一个立场; -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(); 

这个技巧似乎表明你已经完成了写入stream。 根据你的SVG的大小,你可能需要注意 Inkscape的背压处理'drain'事件。


至于传递一个stream到child_process.spawn调用中,您需要使用'pipe'选项,然后将可读的stream传child.stdin ,如下所示。 我知道这在节点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); 

显然,这个方法有点复杂,除非你有足够的理由(你正在有效地实现你自己的可读string),否则你应该使用上面的方法。

注意: readable._push函数必须根据文档来实现,但不一定要做任何事情。

所以,我想出了一个解决方法。 这似乎有点破解,但它工作得很好。

首先,我做了这一行的shell脚本:

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

然后,我只是产生该文件,并写入标准input,如下所示:

 cmd = spawn("shell_script"); cmd.stdin.write(svg); cmd.stdin.end(); cmd.stdout.pipe(pipe); 

我真的认为这应该没有shell脚本,但它不会(至less对我来说)。 这可能是一个Node.js错误。

问题来自于节点中的文件描述符是套接字,并且如果是套接字,linux(也可能是大多数Unices)不会让你打开/ dev / stdin。

我在https://github.com/nodejs/node-v0.x-archive/issues/3530#issuecomment-6561239上find了bnoordhuis的解&#x91CA;

给出的解决scheme接近@ nmrugg的答案:

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

进一步的工作后,你现在可以使用https://www.npmjs.com/package/posix-pipe模块来确保进程看到一个不是套接字的stdin&#x3002;

看看这个模块中“应该把数据传给subprocess”的testing归结为什么

 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导入,但是它已经在他们的Wishlist上。