| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 34daaa7 commit c3bb4b1
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -77,11 +77,12 @@ The importance of the distinction between `child_process.exec()` and | |||
| 77 | 77 | `child_process.execFile()` can vary based on platform. On Unix-type operating | |
| 78 | 78 | systems (Unix, Linux, OSX) `child_process.execFile()` can be more efficient | |
| 79 | 79 | because it does not spawn a shell. On Windows, however, `.bat` and `.cmd` | |
| 80 | - files are not executable on their own without a terminal and therefore cannot | ||
| 81 | - be launched using `child_process.execFile()` (or even `child_process.spawn()`). | ||
| 82 | - When running on Windows, `.bat` and `.cmd` files can only be invoked using | ||
| 83 | - either `child_process.exec()` or by spawning `cmd.exe` and passing the `.bat` | ||
| 84 | - or `.cmd` file as an argument (which is what `child_process.exec()` does). | ||
| 80 | + files are not executable on their own without a terminal, and therefore cannot | ||
| 81 | + be launched using `child_process.execFile()`. When running on Windows, `.bat` | ||
| 82 | + and `.cmd` files can be invoked using `child_process.spawn()` with the `shell` | ||
| 83 | + option set, with `child_process.exec()`, or by spawning `cmd.exe` and passing | ||
| 84 | + the `.bat` or `.cmd` file as an argument (which is what the `shell` option and | ||
| 85 | + `child_process.exec()` do). | ||
| 85 | 86 | ||
| 86 | 87 | ```js | |
| 87 | 88 | // On Windows Only ... | |
@@ -277,6 +278,10 @@ not clone the current process.* | |||
| 277 | 278 | [`options.detached`][]) | |
| 278 | 279 | * `uid` {Number} Sets the user identity of the process. (See setuid(2).) | |
| 279 | 280 | * `gid` {Number} Sets the group identity of the process. (See setgid(2).) | |
| 281 | + * `shell` {Boolean|String} If `true`, runs `command` inside of a shell. Uses | ||
| 282 | + '/bin/sh' on UNIX, and 'cmd.exe' on Windows. A different shell can be | ||
| 283 | + specified as a string. The shell should understand the `-c` switch on UNIX, | ||
| 284 | + or `/s /c` on Windows. Defaults to `false` (no shell). | ||
| 280 | 285 | * return: {ChildProcess object} | |
| 281 | 286 | ||
| 282 | 287 | The `child_process.spawn()` method spawns a new process using the given | |
@@ -581,6 +586,10 @@ throw. The [`Error`][] object will contain the entire result from | |||
| 581 | 586 | * `maxBuffer` {Number} largest amount of data (in bytes) allowed on stdout or | |
| 582 | 587 | stderr - if exceeded child process is killed | |
| 583 | 588 | * `encoding` {String} The encoding used for all stdio inputs and outputs. (Default: 'buffer') | |
| 589 | + * `shell` {Boolean|String} If `true`, runs `command` inside of a shell. Uses | ||
| 590 | + '/bin/sh' on UNIX, and 'cmd.exe' on Windows. A different shell can be | ||
| 591 | + specified as a string. The shell should understand the `-c` switch on UNIX, | ||
| 592 | + or `/s /c` on Windows. Defaults to `false` (no shell). | ||
| 584 | 593 | * return: {Object} | |
| 585 | 594 | * `pid` {Number} Pid of the child process | |
| 586 | 595 | * `output` {Array} Array of results from stdio output | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -71,7 +71,8 @@ exports._forkChild = function(fd) { | |||
| 71 | 71 | ||
| 72 | 72 | ||
| 73 | 73 | function normalizeExecArgs(command /*, options, callback*/) { | |
| 74 | - var file, args, options, callback; | ||
| 74 | + let options; | ||
| 75 | + let callback; | ||
| 75 | 76 | ||
| 76 | 77 | if (typeof arguments[1] === 'function') { | |
| 77 | 78 | options = undefined; | |
@@ -81,25 +82,12 @@ function normalizeExecArgs(command /*, options, callback*/) { | |||
| 81 | 82 | callback = arguments[2]; | |
| 82 | 83 | } | |
| 83 | 84 | ||
| 84 | - if (process.platform === 'win32') { | ||
| 85 | - file = process.env.comspec || 'cmd.exe'; | ||
| 86 | - args = ['/s', '/c', '"' + command + '"']; | ||
| 87 | - // Make a shallow copy before patching so we don't clobber the user's | ||
| 88 | - // options object. | ||
| 89 | - options = util._extend({}, options); | ||
| 90 | - options.windowsVerbatimArguments = true; | ||
| 91 | - } else { | ||
| 92 | - file = '/bin/sh'; | ||
| 93 | - args = ['-c', command]; | ||
| 94 | - } | ||
| 95 | - | ||
| 96 | - if (options && options.shell) | ||
| 97 | - file = options.shell; | ||
| 85 | + // Make a shallow copy so we don't clobber the user's options object. | ||
| 86 | + options = Object.assign({}, options); | ||
| 87 | + options.shell = typeof options.shell === 'string' ? options.shell : true; | ||
| 98 | 88 | ||
| 99 | 89 | return { | |
| 100 | - cmd: command, | ||
| 101 | - file: file, | ||
| 102 | - args: args, | ||
| 90 | + file: command, | ||
| 103 | 91 | options: options, | |
| 104 | 92 | callback: callback | |
| 105 | 93 | }; | |
@@ -109,7 +97,6 @@ function normalizeExecArgs(command /*, options, callback*/) { | |||
| 109 | 97 | exports.exec = function(command /*, options, callback*/) { | |
| 110 | 98 | var opts = normalizeExecArgs.apply(null, arguments); | |
| 111 | 99 | return exports.execFile(opts.file, | |
| 112 | - opts.args, | ||
| 113 | 100 | opts.options, | |
| 114 | 101 | opts.callback); | |
| 115 | 102 | }; | |
@@ -123,7 +110,8 @@ exports.execFile = function(file /*, args, options, callback*/) { | |||
| 123 | 110 | maxBuffer: 200 * 1024, | |
| 124 | 111 | killSignal: 'SIGTERM', | |
| 125 | 112 | cwd: null, | |
| 126 | - env: null | ||
| 113 | + env: null, | ||
| 114 | + shell: false | ||
| 127 | 115 | }; | |
| 128 | 116 | ||
| 129 | 117 | // Parse the optional positional parameters. | |
@@ -153,6 +141,7 @@ exports.execFile = function(file /*, args, options, callback*/) { | |||
| 153 | 141 | env: options.env, | |
| 154 | 142 | gid: options.gid, | |
| 155 | 143 | uid: options.uid, | |
| 144 | + shell: options.shell, | ||
| 156 | 145 | windowsVerbatimArguments: !!options.windowsVerbatimArguments | |
| 157 | 146 | }); | |
| 158 | 147 | ||
@@ -331,7 +320,23 @@ function normalizeSpawnArguments(file /*, args, options*/) { | |||
| 331 | 320 | else if (options === null || typeof options !== 'object') | |
| 332 | 321 | throw new TypeError('"options" argument must be an object'); | |
| 333 | 322 | ||
| 334 | - options = util._extend({}, options); | ||
| 323 | + // Make a shallow copy so we don't clobber the user's options object. | ||
| 324 | + options = Object.assign({}, options); | ||
| 325 | + | ||
| 326 | + if (options.shell) { | ||
| 327 | + const command = [file].concat(args).join(' '); | ||
| 328 | + | ||
| 329 | + if (process.platform === 'win32') { | ||
| 330 | + file = typeof options.shell === 'string' ? options.shell : | ||
| 331 | + process.env.comspec || 'cmd.exe'; | ||
| 332 | + args = ['/s', '/c', '"' + command + '"']; | ||
| 333 | + options.windowsVerbatimArguments = true; | ||
| 334 | + } else { | ||
| 335 | + file = typeof options.shell === 'string' ? options.shell : '/bin/sh'; | ||
| 336 | + args = ['-c', command]; | ||
| 337 | + } | ||
| 338 | + } | ||
| 339 | + | ||
| 335 | 340 | args.unshift(file); | |
| 336 | 341 | ||
| 337 | 342 | var env = options.env || process.env; | |
@@ -491,12 +496,12 @@ function execFileSync(/*command, args, options*/) { | |||
| 491 | 496 | exports.execFileSync = execFileSync; | |
| 492 | 497 | ||
| 493 | 498 | ||
| 494 | - function execSync(/*command, options*/) { | ||
| 499 | + function execSync(command /*, options*/) { | ||
| 495 | 500 | var opts = normalizeExecArgs.apply(null, arguments); | |
| 496 | 501 | var inheritStderr = opts.options ? !opts.options.stdio : true; | |
| 497 | 502 | ||
| 498 | - var ret = spawnSync(opts.file, opts.args, opts.options); | ||
| 499 | - ret.cmd = opts.cmd; | ||
| 503 | + var ret = spawnSync(opts.file, opts.options); | ||
| 504 | + ret.cmd = command; | ||
| 500 | 505 | ||
| 501 | 506 | if (inheritStderr) | |
| 502 | 507 | process.stderr.write(ret.stderr); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,64 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + const assert = require('assert'); | ||
| 4 | + const cp = require('child_process'); | ||
| 5 | + | ||
| 6 | + // Verify that a shell is, in fact, executed | ||
| 7 | + const doesNotExist = cp.spawn('does-not-exist', {shell: true}); | ||
| 8 | + | ||
| 9 | + assert.notEqual(doesNotExist.spawnfile, 'does-not-exist'); | ||
| 10 | + doesNotExist.on('error', common.fail); | ||
| 11 | + doesNotExist.on('exit', common.mustCall((code, signal) => { | ||
| 12 | + assert.strictEqual(signal, null); | ||
| 13 | + | ||
| 14 | + if (common.isWindows) | ||
| 15 | + assert.strictEqual(code, 1); // Exit code of cmd.exe | ||
| 16 | + else | ||
| 17 | + assert.strictEqual(code, 127); // Exit code of /bin/sh | ||
| 18 | + })); | ||
| 19 | + | ||
| 20 | + // Verify that passing arguments works | ||
| 21 | + const echo = cp.spawn('echo', ['foo'], { | ||
| 22 | + encoding: 'utf8', | ||
| 23 | + shell: true | ||
| 24 | + }); | ||
| 25 | + let echoOutput = ''; | ||
| 26 | + | ||
| 27 | + assert.strictEqual(echo.spawnargs[echo.spawnargs.length - 1].replace(/"/g, ''), | ||
| 28 | + 'echo foo'); | ||
| 29 | + echo.stdout.on('data', data => { | ||
| 30 | + echoOutput += data; | ||
| 31 | + }); | ||
| 32 | + echo.on('close', common.mustCall((code, signal) => { | ||
| 33 | + assert.strictEqual(echoOutput.trim(), 'foo'); | ||
| 34 | + })); | ||
| 35 | + | ||
| 36 | + // Verify that shell features can be used | ||
| 37 | + const cmd = common.isWindows ? 'echo bar | more' : 'echo bar | cat'; | ||
| 38 | + const command = cp.spawn(cmd, { | ||
| 39 | + encoding: 'utf8', | ||
| 40 | + shell: true | ||
| 41 | + }); | ||
| 42 | + let commandOutput = ''; | ||
| 43 | + | ||
| 44 | + command.stdout.on('data', data => { | ||
| 45 | + commandOutput += data; | ||
| 46 | + }); | ||
| 47 | + command.on('close', common.mustCall((code, signal) => { | ||
| 48 | + assert.strictEqual(commandOutput.trim(), 'bar'); | ||
| 49 | + })); | ||
| 50 | + | ||
| 51 | + // Verify that the environment is properly inherited | ||
| 52 | + const env = cp.spawn(`"${process.execPath}" -pe process.env.BAZ`, { | ||
| 53 | + env: Object.assign({}, process.env, {BAZ: 'buzz'}), | ||
| 54 | + encoding: 'utf8', | ||
| 55 | + shell: true | ||
| 56 | + }); | ||
| 57 | + let envOutput = ''; | ||
| 58 | + | ||
| 59 | + env.stdout.on('data', data => { | ||
| 60 | + envOutput += data; | ||
| 61 | + }); | ||
| 62 | + env.on('close', common.mustCall((code, signal) => { | ||
| 63 | + assert.strictEqual(envOutput.trim(), 'buzz'); | ||
| 64 | + })); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,37 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + const assert = require('assert'); | ||
| 4 | + const cp = require('child_process'); | ||
| 5 | + | ||
| 6 | + // Verify that a shell is, in fact, executed | ||
| 7 | + const doesNotExist = cp.spawnSync('does-not-exist', {shell: true}); | ||
| 8 | + | ||
| 9 | + assert.notEqual(doesNotExist.file, 'does-not-exist'); | ||
| 10 | + assert.strictEqual(doesNotExist.error, undefined); | ||
| 11 | + assert.strictEqual(doesNotExist.signal, null); | ||
| 12 | + | ||
| 13 | + if (common.isWindows) | ||
| 14 | + assert.strictEqual(doesNotExist.status, 1); // Exit code of cmd.exe | ||
| 15 | + else | ||
| 16 | + assert.strictEqual(doesNotExist.status, 127); // Exit code of /bin/sh | ||
| 17 | + | ||
| 18 | + // Verify that passing arguments works | ||
| 19 | + const echo = cp.spawnSync('echo', ['foo'], {shell: true}); | ||
| 20 | + | ||
| 21 | + assert.strictEqual(echo.args[echo.args.length - 1].replace(/"/g, ''), | ||
| 22 | + 'echo foo'); | ||
| 23 | + assert.strictEqual(echo.stdout.toString().trim(), 'foo'); | ||
| 24 | + | ||
| 25 | + // Verify that shell features can be used | ||
| 26 | + const cmd = common.isWindows ? 'echo bar | more' : 'echo bar | cat'; | ||
| 27 | + const command = cp.spawnSync(cmd, {shell: true}); | ||
| 28 | + | ||
| 29 | + assert.strictEqual(command.stdout.toString().trim(), 'bar'); | ||
| 30 | + | ||
| 31 | + // Verify that the environment is properly inherited | ||
| 32 | + const env = cp.spawnSync(`"${process.execPath}" -pe process.env.BAZ`, { | ||
| 33 | + env: Object.assign({}, process.env, {BAZ: 'buzz'}), | ||
| 34 | + shell: true | ||
| 35 | + }); | ||
| 36 | + | ||
| 37 | + assert.strictEqual(env.stdout.toString().trim(), 'buzz'); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments