我尝试通过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"]});
我尝试将流传递给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
答案 0 :(得分:9)
好吧,我没有Inkscape,但这似乎解决了Node.js方面的问题。我在Inkscape中使用wc
作为支持者; -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();
这个技巧似乎表明你已经完成了对流的写作。根据SVG的大小,您可能需要通过处理'drain'
事件从Inkscape pay attention to backpressure开始。
至于将流传递到child_process.spawn
调用,您需要使用'pipe'
选项,然后将可读流传输到child.stdin
,如下所示。我知道这在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);
显然,这个方法有点复杂,你应该使用上面的方法,除非你有充分的理由(你有效地实现了你自己的可读字符串)。
注意:readable._push
函数必须根据docs实现,但不一定要做任何事情。
答案 1 :(得分:5)
所以,我想出了一个解决方法。这看起来有点像黑客,但它的工作正常。
首先,我制作了这个单行shell脚本:
cat | inkscape -z -f /dev/stdin -A /dev/stdout | cat
然后,我只是生成该文件并写入stdin,如下所示:
cmd = spawn("shell_script");
cmd.stdin.write(svg);
cmd.stdin.end();
cmd.stdout.pipe(pipe);
我真的认为这应该可以在没有shell脚本的情况下工作,但它不会(至少对我来说)。这可能是Node.js的错误。
答案 2 :(得分:5)
问题来自于节点中的文件描述符是套接字并且linux(可能是大多数Unices)如果它是套接字而不能让你打开/ dev / stdin。
我在https://github.com/nodejs/node-v0.x-archive/issues/3530#issuecomment-6561239
上找到了bnoordhuis的解释给定的解决方案接近@ nmrugg的回答:
var run = spawn("sh", ["-c", "cat | your_command_using_dev_stdin"]);
进一步的工作之后,您现在可以使用https://www.npmjs.com/package/posix-pipe模块来确保进程看到的stdin不是套接字。
看看&#39;应该将数据传递给子进程&#39;在这个模块中进行测试,归结为
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])
答案 3 :(得分:0)
如Inkscape bug 171016所示,Inkscape不支持通过stdin导入,但它在愿望清单上。