Pipe Node stdout in realtime - node.js

I have a spawn process running a docker pull and I'm using the following:
const proc = spawn('docker', [ 'pull', 'some/container' ], { env: process.env, cwd: process.env.HOME })
proc.stdout.pipe(process.stdout)
As it runs it breaks up and downloads the individual SHA's and the above works pretty well, however, it puts each response on a new line. I'm curious if there's a way to emulate the "normal" output so each line writes as it pull the image.

If you're just piping to process.stdout, then you could just set the stdio option like:
const proc = spawn('docker', [
'pull',
'some/container'
], {
env: process.env,
cwd: process.env.HOME,
stdio: ['pipe', process.stdout, 'pipe']
});
The end result being that docker will now see its stdout as a TTY (assuming this node script is being run from a terminal/pty of course) and not a pipe.

Related

nodejs run a bash script using spawn

I know this question has been asked many times but I have tried most of the methods and they just don't work for me.
So here is my problem, I have a simple bash script like this
#!/bin/bash
echo "Username: $1";
echo %DATABASE_URL%;
I want to run this script in a separate process. so if the parent process gets killed during my script being excused it still continues running.
Here is my nodejs code
const child = spawn('bash', [`script.sh`, 'test'], {
detached: true,
cwd: process.cwd(),
detached: true,
stdio: "inherit",
DATABASE_URL: 'test'
}, function (err, stdout, stderr) {
// Node.js does not invoke this
console.log(stdout);
stdout.on("data", data => {
console.log('Output of script execution');
});
stderr.on("data", data => {
console.log('an error with file system');
});
});
child.unref();
child.on('exit', (code) => {
console.log("Child exited");
});
So I know that my script returns some output and should run callback but it does not run it. It directly jumps to the on.('exit') callback which confuses me.
Also it worth mentioning that I am testing the code on windows and bash script.sh 'test' works if I run it on cmd.
Posts I have tried:
How to run shell script file using nodejs?
Execute script from Node in a separate process
Bash Script : what does #!/bin/bash mean?
and many of the existing weblogs that explains the same.

nodejs spawn not constructing valid vim command

If I have this script in node, saved as example.js:
const childProcess = require('child_process');
childProcess.spawn('vim', ['-u NONE', 'test.txt'], { stdio: 'inherit' });
I would expect that node example.js would be (roughly) equivalent to calling:
vim -u NONE test.txt
However, when I execute the script I get:
$ node example.js
VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Dec 26 2020 07:37:17)
Garbage after option argument: "-u NONE"
More info with: "vim -h"
Running vim -u NONE example.txt directly works just fine.
Am I misunderstanding / misusing spawn somehow?
Edit:
This, without the -u NONE flag, works just fine:
childProcess.spawn('vim', ['test.txt'], { stdio: 'inherit' });
It's adding -u NONE that for some reason vim doesn't like.
This should work
const cp = spawn('vim', ['test.txt'], {stdio: ['inherit']})
cp.stdout.pipe(process.stdout)
Spawn open a child_process which is attached to the const cp(in this ex), this method stream its output (https://nodejs.org/dist/latest-v14.x/docs/api/child_process.html), so we need to consume it. We pipe the cp.stdout to the parent_process process.stdout. That open a new tty within: the child_process.stdout
We can make it more straightforward by setting the stdio childProcess.output option to 'inherit' and(optional) forwarding the childProcess.stderr to its own childProcess.stdout (which is already inherit by the motherProcess, so will be output automatically).
This should output the same as previously
const cp = spawn(
'vim', ['test.txt'],
{stdio: ['inherit', 'inherit', process.stdout]}
)
To run precisely the command vim -u NONE file.ext. The first argument is the executable path and the second is an array containing the flags to pass to the command. Inside this array each single element(separate with space) of the flags must be an element of the array. So in this case that should work
const cp = spawn(
'vim', ['-u', 'NONE', 'test.txt'],
{stdio: ['inherit', 'inherit', process.stdout]}
)
You could use it like this:
const { exec } = require("child-process");
exec('vim -u NONE example.txt', (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log(stdout);
});

'Invalid Verb' error only when Calling Inkscape as a subprocess

When I call the following in the command line it works like a charm:
inkscape --with-gui --batch-process --export-filename=- \
--actions="select-all;ObjectToPath" \
/full/path/to/example.svg
But when I open Node.js and make the same call in a subprocess like so:
const cp = require("child_process");
var child = cp.spawn(
"/usr/bin/inkscape",
[
"--with-gui",
"--batch-process",
"--export-filename=-",
'--actions="select-all;ObjectToPath"',
"/full/path/to/example.svg",
],
{
cwd: process.cwd(),
detached: true,
stdio: "inherit",
}
);
I get the following error:
Unable to find: "select-all
verbs_action: Invalid verb: "select-all
Unable to find: ObjectToPath"
verbs_action: Invalid verb: ObjectToPath"
and the file is returned (printed to stdout) unchanged. Any Idea why the verbs are not found when running Inkscape as a subprocess but not calling it directly from the terminal? I get this same error on ubuntu (20.04) and OSX using the latest Inkscape (1.0.1+r73).
When you use cp.spawn with an array of arguments, you don't need to internally quote "select-all;ObjectToPath" like you would with a shell. (In a shell, the quotes prevent the shell from tokenizing the command line into two lines. Due to the same mechanism - or lack thereof - attempting to use shell variables such as $$ or environment variables such as $PATH would fail when you use cp.spawn, since there's nothing to parse that.)
I would imagine
const cp = require("child_process");
var child = cp.spawn(
"/usr/bin/inkscape",
[
"--with-gui",
"--batch-process",
"--export-filename=-",
"--actions=select-all;ObjectToPath",
"/full/path/to/example.svg",
],
{
cwd: process.cwd(),
detached: true,
stdio: "inherit",
},
);
would do the trick for you.

node.js - starting a cmd with an infinitely running process

i have following code on node for windows:
var spawn = require('child_process').spawn,
out = fs.openSync('./out.log', 'a'),
err = fs.openSync('./out.log', 'a');
spawn('cmd', [ '/c', 'start', '""', __dirname + tstDir + 'bin/test.bat', 'agent', ' -f ', configuration.path2lgst + 'test.conf' ], {
stdio: [ 'ignore', out, err ], // piping stdout and stderr to out.log
detached: true
}).unref();
In general i want to start a cmd which executes a .bat file that runs a process infinetly. node.js should return after this is initiated.
The problem is that what ever i try, either the cmd exits when node finished starting the cmd with the batch file or everything starts fine (like above code) but the process in node.js never returns.
Any ideas what could be done??
Cheers
Thorsten

Format Node Stdout Pipe

I've got the following setup to run a number of spawned processes:
spawn(proc, args, {
env: process.env,
cwd: process.env.HOME,
stdio: [ 'pipe', process.stdout, process.stdout ]
});
My curiosity lies in the output streams. I'm curious if there is a way to have the output indented 2 characters? I'd like to have the process' output clearly distinguished.

Resources