processes started via `exec` are unable to accept input
If I try to launch npm init from a shelljs script it seems that the stdin is not passed through to that process:
require('shelljs/global')
exec('npm init')
=>
exec npm init { stdio: 'inherit' }
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (drive) foobar
Pressing enter has no effect.
Node version?
v5.8.0
Confirmed as a bug.
As a workaround, please use child_process.execSync('npm init', {stdio: 'inherit'});
Fixes are welcomed.
There are several ways to fix this issue. In the exec.js source file, you can either :
- Pipe process.stdin to childProcess.stdin
process.stdin.pipe(childProcess.stdin); - Use spawn instead of exec in your string scriptFile
- Execute the command and not the scriptFile in execSync
The main problem is that i can't understand why you have to build a script in a script. execSync can run a command.
script = [
"var child = require('child_process')",
" , fs = require('fs');",
"var childProcess = child.exec('"+escape(cmd)+"', {env: process.env, maxBuffer: "+opts.maxBuffer+"}, function(err) {",
" fs.writeFileSync('"+escape(codeFile)+"', err ? err.code.toString() : '0');",
"});",
"var stdoutStream = fs.createWriteStream('"+escape(stdoutFile)+"');",
"var stderrStream = fs.createWriteStream('"+escape(stderrFile)+"');",
"childProcess.stdout.pipe(stdoutStream, {end: false});",
"childProcess.stderr.pipe(stderrStream, {end: false});",
"childProcess.stdout.pipe(process.stdout);",
"childProcess.stderr.pipe(process.stderr);",
"var stdoutEnded = false, stderrEnded = false;",
"function tryClosingStdout(){ if(stdoutEnded){ stdoutStream.end(); } }",
"function tryClosingStderr(){ if(stderrEnded){ stderrStream.end(); } }",
"childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosingStdout(); });",
"childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosingStderr(); });"
].join('\n');
@MatthieuLemoine
The main problem is that i can't understand why you have to build a script in a script. execSync can run a command.
This is a pretty ancient part of the code base that's stuck around because it allows us to send command output to the terminal in real-time while still capturing it for when the function returns. Even with backwards compatibility in mind, there's probably a much smarter way to revise this function. Pull requests, as always, are welcome :smile:
One solution that comes to mind would be, as you suggested, to use spawn(). The main drawback is that it doesn't support glob characters (as far as I'm aware). This would be nice, however, as an option for situations where globbing isn't necessary (it would fix some of the security concerns surrounding globbing, too!).
I'm going to try to re-write exec using some of my work from #402.
@ariporad So is there any reason execAsync does the following instead of just using the {stdio: 'inherit'} option?
c.stdout.on('data', function (data) {
stdout += data;
if (!opts.silent) process.stdout.write(data);
});
c.stderr.on('data', function (data) {
stderr += data;
if (!opts.silent) process.stderr.write(data);
});
@jedwards1211: Yes... There is no other way to capture stdout from the child.
Oh right. I've noticed that for some reason transient output like npm's progress bar works when I use inherit but not when I do something like the above (or better, do c.stdout.pipe(process.stdout)). I haven't figured out why that is. But it might be nice to have an option to use inherit and not capture output for that purpose.
I added the workaround to the FAQs: https://github.com/shelljs/shelljs/wiki/FAQ#running-interactive-programs-with-exec
Has anyone found a fix for this because it is still a problem in shelljs v0.8.3
@RastogiAbhijeet https://github.com/shelljs/shelljs/wiki/FAQ#running-interactive-programs-with-exec
Is there any chance I can help in fixing this issue ?