Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node js: Executing command line (opening a file)

Tags:

node.js

cmd

I am trying to open a file through the command line by using node. I am using child_process.spawn, here is the code

var 
    process = require('child_process'),
    cmd = process.spawn('cmd', ['start','tmp.txt'], {cwd: 'C:\\Users\\testuser\\Node_dev'});

I am expecting the file tmp.txt located in the Node_dev folder to be opened but I am getting the error -

dir error { [Error: spawn ENOENT] code: 'ENONENT', errno: 'ENOENT', syscall: 'spawn'

What am I missing?

Also, what's the difference between child_process.spawn vs child_process.exec for this?

like image 540
lboyel Avatar asked Jan 23 '26 04:01

lboyel


2 Answers

I don't have an explanation for your ENOENT error [update: turns out this was a red herring], but one problem with your command is that you launch cmd.exe without /c, meaning that the shell spawned will (a) stay open and (b) actually ignore the specified command.

As for how the child_process module's methods differ:

.execFile and .exec take a callback that reports a single, buffered result, whereas .spawn provides chunked output via events.
Only .exec passes the command to the platform's default shell, which makes it more convenient, but less efficient.

In your case, you don't care about output returned from the spawned command, and since you need to involve the shell anyway,.exec is the best choice.

On Windows, use of start comes with its own pitfalls:

  • It is not an executable, but a shell builtin (to put it in Unix terms) - thus, it must be invoked via cmd.exe.
  • If its 1st argument is a [double-quoted] value with embedded spaces, it is interpreted as a window title rather than a filename argument; thus, to robustly pass a filename argument, you must pass an empty window title as the 1st argument.

Here are invocations that should work on Windows - note that both launch the child process asynchronously and ignore any output from it - all they do is to tell cmd.exe to open the specified file as if a user had opened it in Explorer:

  • using .exec:
var cpm = require('child_process');

// With .exec, specify the entire shell command as the 1st argument - it is implicitly
// passed to cmd.exe.
// '""' as the 1st argument to `start` is an empty window title that ensures that any 
// filename argument with embedded spaces isn't mistaken for a window title.
cpm.exec('start "" "tmp.txt"', {cwd: 'C:\\Users\\testuser\\Node_dev'});
  • using .execFile or .spawn:
// With .spawn or .execFile, specify `cmd` as the 1st argument, and the shell command 
// tokens as an array passed as the 2nd argument.
// Note the /c, which ensures that cmd exits after having executed the specified 
// command.
// '""' as the 1st argument to `start` is an empty window title that ensures that any 
// filename argument with embedded spaces isn't mistaken for a window title.
cpm.spawn('cmd', [ '/c', 'start', '""', 'tmp.txt' ], {cwd: 'C:\\Users\\testuser\\Node_dev'});
like image 192
mklement0 Avatar answered Jan 25 '26 19:01

mklement0


There is a cross-platform module on npm called open that opens files using the OS's default handler that you could use as a guide or just use it as-is.

To do it manually with spawn on Windows though, you'd do something like:

var args = ['/s', '/c', 'start', '', 'tmp.txt'],
    opts = { cwd: 'C:\\Users\\testuser\\Node_dev' },
    child = child_process.spawn('cmd.exe', args, opts);

child_process.exec() is basically a higher-level wrapper for child_process.spawn() which buffers output and then passes the buffered stdout and stderr output to a callback.

like image 26
mscdex Avatar answered Jan 25 '26 18:01

mscdex



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!