cannot create /dev/stdout: No such device or address

做~自己de王妃 提交于 2019-12-10 17:15:00

问题


I'm want to run a shell command via node and capture the result of stdout. My script works fine on OSX, but not on Ubuntu.

I've simplified the problem and script to the following node script:

var execSync = require('child_process').execSync,
    result = execSync('echo "hello world" >> /dev/stdout');

// Do something with result

Results in:

/bin/sh: 1: cannot create /dev/stdout: No such device or address

  • I have tried replacing /dev/stdout with /dev/fd/1
  • I have tried changing the shell to bash... execSync('echo ...', {shell : '/bin/bash'})

Like I said, the problem above is simplified. The real script accepts as a parameter the name of a file where results should be written, so I need to resolve this by providing access to the stdout stream as a file descriptor, i.e. /dev/stdout.

How can I execute a command via node, while giving the command access to its own stdout stream?


回答1:


On /dev/stdout

I don't have access to an OSX box, but from this issue on phantomjs, it seems that while on both OSX/BSD and Linux /dev/stdout is a symlink, nonetheless it seems to work differently between them. One of the commenters said it's standard on OSX to use /dev/stdout but not for Linux. In another random place I read statements that imply /dev/stdout is pretty much an OSX thing. There might be a clue in this answer as to why it doesn't work on Linux (seems to implicitly close the file descriptor when used this way).

Further related questions:

  • https://unix.stackexchange.com/questions/36403/portability-of-dev-stdout
  • bash redirect to /dev/stdout: Not a directory

The solution

I tried your code on Arch and it indeed gives me the same error, as do the variations mentioned - so this is not related to Ubuntu.

I found a blog post that describes how you can pass a file descriptor to execSync. Putting that together with what I got from here and here, I wrote this modified version of your code:

var fs = require('fs');
var path = require('path');

var fdout = fs.openSync(path.join(process.cwd(), 'stdout.txt'), 'a');
var fderr = fs.openSync(path.join(process.cwd(), 'stderr.txt'), 'a');

var execSync = require('child_process').execSync,
    result = execSync('echo "hello world"', {stdio: [0,fdout,fderr] });

Unless I misunderstood your question, you want to be able to change where the output of the command in execSync goes. With this you can, using a file descriptor. You can still pass 1 and 2 if you want the called program to output to stdout and stderr as inherited by its parent, which you've already mentioned in the comments.

For future reference, this worked on Arch with kernel version 4.10.9-1-ARCH, on bash 4.4.12 and node v7.7.3.



来源:https://stackoverflow.com/questions/40301841/cannot-create-dev-stdout-no-such-device-or-address

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!