Intro
When I call another software from Node.js, I use "child_process" like this.
"child_process" has four kind of methods(exclude "Sync" mehtods).
- exec
- execFile
- fork
- spawn
Because I wanted to know how to use them properly, I will try them.
Environments
- Node.js ver.16.3.0
- ts-node ver.10.0.0
- TypeScript ver.4.3.2
child_process.spawn()
According to the documents, they are based on "child_process.spawn()".
index.ts
import { exec, execFile, fork, spawn } from "child_process";
import path, { resolve } from "path/posix";
function start() {
spawnSample('powershell',['node', '-v']);
}
function spawnSample(command: string, args: string[]) {
const execProcess = spawn(command, args);
console.log('spawn');
console.log(execProcess.spawnfile);
execProcess.on('spawn', () => {
console.log('spawn on spawn');
});
execProcess.stdout.on('data', (data) => {
console.log(`spawn stdout: ${data}`);
});
execProcess.stderr.on('data', (data) => {
console.log(`spawn on error ${data}`);
});
execProcess.on('exit', (code, signal) => {
console.log(`spawn on exit code: ${code} signal: ${signal}`);
});
execProcess.on('close', (code: number, args: any[])=> {
console.log(`spawn on close code: ${code} args: ${args}`);
});
}
start();
Results
spawn
powershell
spawn on spawn
spawn stdout: v16.3.0
spawn on exit code: 0 signal: null
spawn on close code: 0 args: null
One important thing is this sample keeps waiting until terminating the child process.
So if I change the arguments of "spawnSample" like "spawnSample('C:\Program Files (x86)\Notepad++\notepad++.exe', []);", I must terminate Notpad++ manually or the sample won't finish.
child_process.exec()
"child_process.exec()" use OS default terminal applications.
On Windows, it uses "C:\WINDOWS\system32\cmd.exe".
To set command-line arguments, I only can use single string value.
index.ts
...
function start() {
...
execSample('node -v');
}
...
function execSample(args: string) {
const execProcess = exec(args, { 'encoding': 'utf8' }, (error, stdout) => {
console.log(`exec stdout: ${stdout} error: ${error}`);
});
console.log('exec spawn');
console.log(execProcess.spawnfile);
execProcess.on('spawn', () => {
console.log('exec on spawn');
});
execProcess.on('error', (err) => {
console.log(`exec on error:${err}`);
});
execProcess.on('exit', (code, signal) => {
console.log(`exec on exit code: ${code} signal: ${signal}`);
});
execProcess.on('close', (code: number, args: any[])=> {
console.log(`exec on close code: ${code} args: ${args}`);
});
}
start();
Results
exec spawn
C:\WINDOWS\system32\cmd.exe
exec on spawn
exec on exit code: 0 signal: null
exec stdout: v16.3.0
error: null
exec on close code: 0 args: null
child_process.execFile()
"child_process.execFile()" can use applications what are first arguments directly as same as "child_process.spawn()".
I think normally I shall use "child_process.execFile()", and when I want to separate calling the applications and callback methods with some reasons, I shall use "child_process.spawn()".
And when I use two or more applications together like the example, I should use "child_process.spawn()".
index.ts
...
function start() {
...
execFileSample('powershell', ['node', '-v']);
}
...
function execFileSample(command: string, args: string[]) {
const execProcess = execFile(command, args, { 'encoding': 'utf8' }, (error, stdout) => {
console.log(`execFile stdout: ${stdout} error: ${error}`);
});
console.log('execFile spawn');
console.log(execProcess.spawnfile);
execProcess.on('on spawn', () => {
console.log('execFile on spawn');
});
execProcess.on('exit', (code, signal) => {
console.log(`execFile on exit code: ${code} signal: ${signal}`);
});
execProcess.on('error', (err) => {
console.log(`execFile on error:${err}`);
});
execProcess.on('close', (code: number, args: any[])=> {
console.log(`execFile on close code: ${code} args: ${args}`);
});
}
start();
Results
execFile spawn
powershell
execFile on exit code: 0 signal: null
execFile stdout: v16.3.0
error: null
execFile on close code: 0 args: null
child_process.fork()
"child_process.fork()" can use to controll child process from parent process.
The example aborts the child process from parent proces.
index.ts
...
function start() {
...
forkSample();
}
...
function forkSample() {
const controller = new AbortController();
const { signal } = controller;
const child = fork(path.join(__dirname, 'sample.js'), ['child'], { signal });
child.on('error', (err: any) => {
// This will be called with err being an AbortError if the controller aborts
});
setTimeout(() => controller.abort(), 5_000);
}
start();
sample.js
function start() {
console.log('hello child sample');
}
start();
Results
hello child sample
One important thing is I can't use this for every applications.
So if I change the first arguments of "child_process.fork()" like "fork("C:/Program Files (x86)/Notepad++/notepad++.exe", ['child'], { signal });", I will get a runtime exception.
C:\Program Files (x86)\Notepad++\notepad++.exe:1
MZďż˝
SyntaxError: Invalid or unexpected token
at Object.compileFunction (node:vm:353:18)
at wrapSafe (node:internal/modules/cjs/loader:1039:15)
at Module._compile (node:internal/modules/cjs/loader:1073:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1138:10)
at Module.load (node:internal/modules/cjs/loader:989:32)
at Function.Module._load (node:internal/modules/cjs/loader:829:14)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12)
at main (C:\Users\example\OneDrive\Documents\workspace\process-sample\node_modules\ts-node\src\bin.ts:246:14)
at Object.<anonymous> (C:\Users\example\OneDrive\Documents\workspace\process-sample\node_modules\ts-node\src\bin.ts:382:3)
at Module._compile (node:internal/modules/cjs/loader:1109:14)
Resources
Get IP address from printer driver names
I can get printer IP addresses from printer driver names by powershell command.
Get-Printer "{Printer Driver Name}"| select portname
I tried this code to get the IP address.
function getIpAddress(printerDriver: string) {
const printerProcess = spawn('powershell', ['Get-Printer', `"${printerDriver}"`]);
const selectProcess = spawn('powershell', ['select', 'portname']);
printerProcess.stdout.on('data', (data) => {
selectProcess.stdin.write(data);
});
selectProcess.stdout.on('data', (data) => {
console.log(data.toString());
});
}
But I got nothing.
Because "selectProcess" didn't wait for stdout of "printerProcess".
After all, I used "exec" and set all commands include the pipe at once.
function getIpAddress(printerDriver: string) {
const printerProcess = exec(`Get-Printer "${printerDriver}"|select portname`, { shell: 'powershell.exe'}, (err, stdout) => {
console.log(stdout);
});
}
Top comments (0)