Node: Quotes are not handled correctly when child_process.spawn() parses args

Created on 3 Feb 2016  路  15Comments  路  Source: nodejs/node

require('child_process')
    .spawn('cmd', ['/c', 'node "my test/__args_out.js" b c d e f'])
    .stderr.addListener("data", data => {console.log(data.toString());});

fails because quotes don't seem to be recognized and parsed by child_process.spawn() as delimiters for parameters with spaces:

Error: Cannot find module 'd:\Documents\VS Code\"my test\__args_out.js"'
    at Function.Module._resolveFilename (module.js:326:15)
    at Function.Module._load (module.js:277:25)
    at Function.Module.runMain (module.js:430:10)
    at startup (node.js:141:18)
    at node.js:980:3

This happens on Windows platforms. I can't tell whether the above error occurs on other platforms, too.


The above code is taken from _jake_ source.

child_process windows

Most helpful comment

The following works for me when command contains nested quotes and spaces.

const command = '"node "foo bar.js" a b c"';
const child = cp.spawn('cmd', ['/s', '/c', command], {windowsVerbatimArguments: true});

All 15 comments

What if you add the /s flag too? That's what child_process.exec() does.

See https://github.com/nodejs/node/blob/4501a28ad98ad897bbfc371026f9c663c1953716/lib/child_process.js#L332-L333

Good call!

I changed as you recommended. And now it works:

require('child_process')
    .spawn('cmd', ['/s', '/c', '"node "my test/__args_out.js" b c d e f"'])
    .stderr.addListener("data", data => {console.log(data.toString());});

It's required to surround the arguments list with additional quotes, too.

@SetTrend did you mean to reopen this?

@TheAlphaNerd :

Yes. I tested with different variations, but to no avail.

I'm currently debugging into what happens when the above code is spawned. Please give me five minutes and I'll come back with a report.

I have now run a number of tests and logged the actual process creation with SysInternals Process Monitor. Here's the result:


Executing above _node_ code, using /s switch:

with surrounding quotes:

.spawn('cmd', ['/s/c', '"node "test/__args_out.js" b c d e f"'])

... results in this system log:

Command line:        cmd /s/c "\"node \"test/__args_out.js\" b c d e f\""
Current directory:   d:\Documents\Visual Studio-Projekte\GitHub\jake\
...
Query open:          D:\"node \"test        NAME INVALID 

:point_right: _The quotes are getting escaped by node._

:red_circle:


without surrounding quotes:

.spawn('cmd', ['/s/c', 'node "test/__args_out.js" b c d e f'])

... results in this system log:

Command line:        cmd /s/c "node \"test/__args_out.js\" b c d e f"
Current directory:   d:\Documents\Visual Studio-Projekte\GitHub\jake\
...
Command line:        node  \"test/__args_out.js\" b c d e f
...
Create file:          D:\Documents\Visual Studio-Projekte\GitHub\jake\"test\__args_out.js"     INVALID NAME
Create file:          D:\Documents\Visual Studio-Projekte\GitHub\jake\"test\__args_out.js".js     INVALID NAME
Create file:          D:\Documents\Visual Studio-Projekte\GitHub\jake\"test\__args_out.js".json     INVALID NAME
Create file:          D:\Documents\Visual Studio-Projekte\GitHub\jake\"test\__args_out.js".node     INVALID NAME
Create file:          D:\Documents\Visual Studio-Projekte\GitHub\jake\"test\__args_out.js"\package.json     INVALID NAME
Create file:          D:\Documents\Visual Studio-Projekte\GitHub\jake\"test\__args_out.js"\index.js     INVALID NAME
Create file:          D:\Documents\Visual Studio-Projekte\GitHub\jake\"test\__args_out.js"\index.json     INVALID NAME
Create file:          D:\Documents\Visual Studio-Projekte\GitHub\jake\"test\__args_out.js"\index.node     INVALID NAME

:point_right: _The quotes are getting escaped by node._

:red_circle:


Executing above _node_ code, NOT using /s switch:

.spawn('cmd', ['/c', '"node "test/__args_out.js" b c d e f"'])
.spawn('cmd', ['/c', 'node "test/__args_out.js" b c d e f'])

:point_right: _Same results as above._

:red_circle:


Running directly from the command line:

D:\Documents\Visual Studio-Projekte\GitHub\jake>cmd /s/c "node "test/__args_out.js" b c d e f"

results in this system log:

Command line:        cmd  /s/c "node "test/__args_out.js" b c d e f"
Current directory:   d:\Documents\Visual Studio-Projekte\GitHub\jake\
...
Create file:          D:\Documents\Visual Studio-Projekte\GitHub\jake\test\__args_out.js     SUCCESS

:point_right: _Successful execution._

:green_heart:


Conclusion:

Apparently, _node_ erroneously escapes quotes when spawning a child process (on Windows platform).

Proposed solution: _node_ should not escape quotes when spawning a child process (on Windows platform).

The following works for me when command contains nested quotes and spaces.

const command = '"node "foo bar.js" a b c"';
const child = cp.spawn('cmd', ['/s', '/c', command], {windowsVerbatimArguments: true});

:open_mouth: Cool. What is that option doing? It doesn't seem to be documented. Let me check here whether I'll get it going, too ...

Thanks a lot for enlighten me on this option. It seems to work.

I may be focussed here ... but before I try to amend a public project like _TypeScript_ (or potentionally any other project on GitHub lacking this option :wink:), can someone please enlighten me on this undocumented option?

  • What does it do on Windows platforms in particular?
  • What does it do on Apple/Linux platforms?
  • It seems that using windowsVerbatimArguments: true is reasonable for using it on any call to child_process.spawn(). What's the reason for not having windowsVerbatimArguments: true be the default behaviour of child_process.spawn() on Windows platforms?

What does it do on Windows platforms in particular?

Tells libuv that the command is a string that can be passed verbatim to cmd.

What does it do on Apple/Linux platforms?

It is silently ignored.

It seems that using windowsVerbatimArguments: true is reasonable for using it on any call to child_process.spawn(). What's the reason for not having windowsVerbatimArguments: true be the default behaviour of child_process.spawn() on Windows platforms?

I'm not sure about that. Probably because it isn't needed in most cases. exec() turns it on by default. In the next stable release, spawn() will support a boolean shell option that will allow you to turn this functionality on, like it is currently done for exec().

@SetTrend can this be closed?

I'm not sure. Shouldn't this behaviour get documented for future use - for both, exec() and spawn()?

The shell option is documented, it just hasn't been in a release yet, so it doesn't show up on the site. Long ago, there was a PR to document windowsVerbatimArguments. Looks like it was closed because the author didn't want to sign the old CLA.

I comprehend. Will the documentation update get released then soon?

What would you suggest on how to proceed? I would very much appreciate to close this issue. On the other hand I would very much appreciate to get the documentation updated final so authors can rely on this feature/option without being required to refer back to this issue.

@SetTrend the state of the documentation in master is available here. If there is anything missing there that you think should be included, you could open a documentation PR. Otherwise, I'm inclined to close this.

Closing given that there does not appear to be anything further to do (other than _perhaps_ some better docs) /cc @nodejs/documentation

Was this page helpful?
0 / 5 - 0 ratings