I cannot get any output in the following code:
var spawn = require('child_process').spawn,
script = 'ftp',
child = spawn(script);
child.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
child.on('close', function (code) {
console.log('child process exited with code ' + code);
});
It works for normal scripts such as 'ls', 'pwd' etc. But not for interactive programs such as 'ftp', 'telnet'. Any suggestions?
Edit:
Take another script for example:
#!/usr/bin/env python
name = raw_input("your name>")
print name
When spawn this script, I wish to fetch the prompt "your name>" with the data event, so that I can latter input something into stdin.
The problem is that I got nothing in the data event, and it seemed that none of these events are triggered.
ls, cat is controllable via input output and error stream.
ftp, telnet is controllable indirectly via tty.
The protocol is also base on input/output stream but it is more complicated. You can use available package to handle that protocol.
https://github.com/chjj/pty.js
var pty = require('pty.js');
var term = pty.spawn('ftp', [], options);
term.on('data', function(data) {
console.log(data);
});
term.write(ftpCmd + '\r');
The author of pty have some interesting examples, he forward pty to web via web socket, including terminal games:
https://github.com/chjj/tty.js
In interactive mode there is a command interpreter that reads user input from stdin, then accodingly prints output. So you have to write to stdin to do something. For example add following lines to your code with telnet command:
child.stdin.write('?\n');
child.stdin.write('quit\n');
Output:
stdout: Commands may be abbreviated. Commands are:
! cr mdir proxy send
$ delete mget sendport site
account debug mkdir put size
append dir mls pwd status
ascii disconnect mode quit struct
bell form modtime quote system
binary get mput recv sunique
bye glob newer reget tenex
case hash nmap rstatus trace
ccc help nlist rhelp type
cd idle ntrans rename user
cdup image open reset umask
chmod lcd passive restart verbose
clear ls private rmdir ?
close macdef prompt runique
cprotect mdelete protect safe
child process exited with code 0
Related
When i run this pidof command by hand, it works. Then put into my server.js.
// send signal to start the install script
var spw = cp.spawn('/sbin/pidof', ['-x', 'wait4signal.py', '|', 'xargs', 'kill', '-USR1']);
spw.stderr.on('data', function(data) {
res.write('----- Install Error !!! -----\n');
res.write(data.toString());
console.log(data.toString());
});
spw.stdout.on('data', function(data) {
res.write('----- Install Data -----\n');
res.write(data.toString());
console.log(data.toString());
});
spw.on('close', function(data) {
res.end('----- Install Finished, please to to status page !!! -----\n');
console.log('88');
});
In the web i only see "----- Install Finished, please to to status page !!!". My install script seems never get this USR1 signal. Anything wrong please ?
The problem is that you have two separate commands. You are piping the output of your /sbin/pidof command to the input stream of your xargs command. If you are using spawn (rather than exec, which a string exactly as you would write on the command line), you need to spawn one process per command.
Spawn your processes like this:
const pidof = spawn('/sbin/pidof', ['-x', 'wait4signal.py']);
const xargs = spawn('xargs', ['kill', '-USR1']);
Now pipe the output of the first process to the input of the second, like so:
pidof.stdout.pipe(xargs.stdin);
Now you can listen to events on your xargs process, like so:
xargs.stdout.on('data', data => {
console.log(data.toString());
});
I'd like to use the execSync method which was added in NodeJS 0.12 but still have the output in the console window from which i ran the Node script.
E.g. if I run a NodeJS script which has the following line I'd like to see the full output of the rsync command "live" inside the console:
require('child_process').execSync('rsync -avAXz --info=progress2 "/src" "/dest"');
I understand that execSync returns the ouput of the command and that I could print that to the console after execution but this way I don't have "live" output...
You can pass the parent´s stdio to the child process if that´s what you want:
require('child_process').execSync(
'rsync -avAXz --info=progress2 "/src" "/dest"',
{stdio: 'inherit'}
);
You can simply use .toString().
var result = require('child_process').execSync('rsync -avAXz --info=progress2 "/src" "/dest"').toString();
console.log(result);
Edit: Looking back on this, I've realised that it doesn't actually answer the specific question because it doesn't show the output to you 'live' — only once the command has finished running.
However, I'm leaving this answer here because I know quite a few people come across this question just looking for how to print the result of the command after execution.
Unless you redirect stdout and stderr as the accepted answer suggests, this is not possible with execSync or spawnSync. Without redirecting stdout and stderr those commands only return stdout and stderr when the command is completed.
To do this without redirecting stdout and stderr, you are going to need to use spawn to do this but it's pretty straight forward:
var spawn = require('child_process').spawn;
//kick off process of listing files
var child = spawn('ls', ['-l', '/']);
//spit stdout to screen
child.stdout.on('data', function (data) { process.stdout.write(data.toString()); });
//spit stderr to screen
child.stderr.on('data', function (data) { process.stdout.write(data.toString()); });
child.on('close', function (code) {
console.log("Finished with code " + code);
});
I used an ls command that recursively lists files so that you can test it quickly. Spawn takes as first argument the executable name you are trying to run and as it's second argument it takes an array of strings representing each parameter you want to pass to that executable.
However, if you are set on using execSync and can't redirect stdout or stderr for some reason, you can open up another terminal like xterm and pass it a command like so:
var execSync = require('child_process').execSync;
execSync("xterm -title RecursiveFileListing -e ls -latkR /");
This will allow you to see what your command is doing in the new terminal but still have the synchronous call.
Simply:
try {
const cmd = 'git rev-parse --is-inside-work-tree';
execSync(cmd).toString();
} catch (error) {
console.log(`Status Code: ${error.status} with '${error.message}'`;
}
Ref: https://stackoverflow.com/a/43077917/104085
// nodejs
var execSync = require('child_process').execSync;
// typescript
const { execSync } = require("child_process");
try {
const cmd = 'git rev-parse --is-inside-work-tree';
execSync(cmd).toString();
} catch (error) {
error.status; // 0 : successful exit, but here in exception it has to be greater than 0
error.message; // Holds the message you typically want.
error.stderr; // Holds the stderr output. Use `.toString()`.
error.stdout; // Holds the stdout output. Use `.toString()`.
}
When command runs successful:
Add {"encoding": "utf8"} in options.
execSync(`pwd`, {
encoding: "utf8"
})
I'm using child_process to run a script that ultimately calls
ssh -t server "sudo command"
I get back:
Pseudo-terminal will not be allocated because stdin is not a terminal.
sudo: sorry, you must have a tty to run sudo
Is there any way to make the process' stdin a terminal? It's being run like so;
var proc = child_process.spawn(pathToCommand, ["args"]);
proc.stdout.on("data", function (data) {
socket.emit("running", "" + data);
});
proc.stderr.on("data", function (err) {
socket.emit("error", "" + err);
});
proc.on("close", function (code) {
socket.emit("finished", "" + code);
});
I would like to avoid forcing terminal allocation for ssh via -tt. Instead I would just like to allocate a terminal for the process. Is this doable?
The ssh2 module allows setting of a pty used by the remote end when using shell() or exec().
I'm trying to create a virtual bash in my node script that executes commands from within another user context.
var spawn = require('child_process').spawn;
var terminal = spawn('bash', [], { uid: 1001 });
terminal.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
terminal.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
terminal.on('close', function (code) {
console.log('child process exited with code ' + code);
});
terminal.stdin.write('echo Hello $USER');
terminal.stdin.end();
After executing this as root the output allways is
Hello root
As you can see in my example I've passed a user id to the spawn, but this doesn't effect anything.
My desired output is (assumed uid 1001's username is 'foobar'):
Hello foobar
Is there a way to do this in node or even a "fake" where I can start a bash process with given user credentials?
TL;DR: Your bash instance has in fact the permission of your foobar user, and the code you wrote is correct.
You can confirm this behavior if you run the following command, instead of bash:
terminal = spawn('id', ['-a'], { uid: 1001 });
which should output this:
stdout: uid=1001(foobar)
Which you can compare to a standard child spawn, without the uid parameter:
terminal = spawn('id', ['-a']);
which outputs:
stdout: uid=0(root)
Here is the relevant explanation, according to this question:
bash detects that it has been started SUID root (UID!=EUID) and uses
its root power to throw this power away, resetting EUID to UID.
which means that when bash starts, it's SUID is root, and then it sets its USER variable to root. Only after that does it uses setuid.
Spawn in nodeJS. I have just about managed to use this to run a bash command as follows. This seems to be pretty much non-blocing and I get action on the browser screen as the command trashes through data.
ls = spawn('find',['/'] );
response.writeHead(200, { "Content-Type": "text/plain" });
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data);
response.write(data);
});
But I want to run a perl script with multiple arguments.
ls = spawn('blah.pl',['--argstring here', '--arg blah'] );
Perl script is just written to get arguments using getopts CPAN lib and it using CPAN expect lib to run though a pile of stuff - outputs to stdout and stderr if I have an error but I mostly care about stdout right now.
The thing is this is giving me no output. Seems to be completely blocking at least until the program finishes execution ... and it this case it doesn't at least for 10 mins.
Am I using spawn wrong?
I like the node module "carrier"
carrier = require "carrier"
childproc = require "child_process"
find = childproc.spawn "find"
find.stdout.setEncoding "utf8"
linereader = carrier.carry find.stdout
linereader.on "line", (line) -> console.log line