How to ignore errors generated by child_process.exec? - javascript

I am executing shell script commands from my nodejs script. One of these commands is "npm install" followed by a command to run the index file of a nodejs file.
The npm install command is returning an error generated by node-gyp. In general, this error does not affect my service. However, child_process.exec is catching it and stopping the script. My questions is, how do I trigger the exec command and ignore the error returned?
Below is a fraction of the code snippet
const exec = require('child_process').exec;
exec("npm install", {
cwd: serviceDirectory + gitRepo
},
(error1, stdout, stderr) => {
if(error1){
//this error is for testing purposes
util.log(error1);
}
//run the service
exec("node index.js",{
cwd: serviceDirectory + gitRepo + "/"
}, cb);
});
}

You can use try-catch to handle the errors with catch, example:
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
export default async function () {
const dataFormat = {
stdout: '',
stderr: '',
};
let cpu = dataFormat;
let diskUsed = dataFormat;
try {
cpu = await exec('top -bn1 | grep "Cpu(s)" | sed "s/.*, *\\([0-9.]*\\)%* id.*/\\1/"');
} catch (error) {
cpu.stderr = error.stderr;
}
try {
diskUsed = await exec("df -h | awk 'NR==2{printf $3}'");
} catch (error) {
diskUsed.stderr = error.stderr;
}
const payload = {
cpu,
diskUsed,
};
return payload
}

Related

Unexpected token '?' using, Discord.js Slash Command handler [duplicate]

I'm not sure what's wrong. I deleted my code and downloaded it then uploaded it again and now I get this error.
Code: https://replit.com/#hi12167pies/webcord#index.js (Click code for code and output for output)
Error:
/home/runner/C8AU9ceLyjc/node_modules/discord.js/src/rest/RESTManager.js:32
const token = this.client.token ?? this.client.accessToken;
^
SyntaxError: Unexpected token '?'
I have no idea whats wrong since it's in the node_modules folder.
If you have problems viewing it here is the code:
const http = require("http")
const discord = require("discord.js")
const client = new discord.Client()
const config = require("./config.json")
const fs = require("fs")
// const readLine = require("readline")
// const rl = readLine.createInterface({
// input: process.stdin,
// output: process.stdout
// })
let msgs = {
"873195510251532348": [],
"873195522633105429": []
}
client.on("ready", () => {
console.log("ready discord")
})
client.on("message", (message) => {
if (message.author.bot) return
if (!config.chats.includes(message.channel.id.toString())) return
msgs[message.channel.id].push({
"username": message.author.tag,
"content": message.content,
"type": "0"
})
})
http.createServer((req,res) => {
const url = req.url.split("?")[0]
let query = {}
req.url.slice(req.url.split("").indexOf("?")).slice(1).split("&").forEach((e) => {
const splited = e.split("=")
query[splited[0]] = splited[1]
})
if (query.q == "messages") {
let msg = []
let i = 0
while (msgs[query.code].length > i) {
const e = msgs[query.code][msgs[query.code].length - (i+1)]
msg.push(e)
i++
}
res.write(JSON.stringify(msg))
res.end()
} else if (query.q == "post") {
let name = query.name.split("%20").join(" ")
let content = query.content.split("%20").join(" ")
client.channels.cache.get(query.code).send(`**${name}**: ${content}`)
msgs[query.code].push({
"username": name,
"content": content,
"type": "1"
})
res.end()
} else if (url == "/robot" && query.istrue == "true") {
res.write("Robot!")
res.end()
} else {
let path
if (!query.code) {
path = "./code.html"
} else {
if (!config.chats.includes(query.code)) {
path = "./invaildcode.html"
} else {
path = "./chat.html"
}
}
fs.readFile(path, (er, da) => {
if (er) res.write("Could not get index.html")
res.write(da)
res.end()
})
}
}).listen(80, (err) => {
if (err) throw err
console.log("listening webserver")
})
client.login(process.env.TOKEN)
I am aware my code is not good right now, I am rewriting it but I still want to know what the error is.
repl.it uses node v12.22.1 but the nullish coalescing operator (??), is relatively new and was added in node v14.
So to use the ?? operator you need to update node in repl.it.
Which you can do by following this repl.it forum post by lukenzy.
Create a file and name it .replit
Inside it, copy and paste the following code:
run = """
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
export NVM_DIR=\"$HOME/.nvm\"
[ -s \"$NVM_DIR/nvm.sh\" ] && \\. \"$NVM_DIR/nvm.sh\"
[ -s \"$NVM_DIR/bash_completion\" ] && \\.\"$NVM_DIR/bash_completion\"
nvm install 14
node index.js
"""
This will install and use the latest Node.js v14 (14.17.4).
If u want to use a different version, change nvm install 14 to any other
number.
Also, change node index.js to the file u want to run.
You are getting this error because you are using an older version of node that didn't support nullable for some packages.
Simply change node version of yours.
You can simply change node versions using 'nvm'. follow this git repo https://github.com/nvm-sh/nvm

Is there a way to get 'live' output lines from a python script spawned by child_process.execFile without flushing stdout every time?

I am trying to get the lines a ('never ending') python script puts into stdout. But currently my code would only log something to the console when the python process exits. Is there a way I can get the 'live' output of the python script line by line?
spawn_child.js:
let execFile = require("child_process").execFile;
var child = execFile("python3", ["PATH_TO_FILE"]);
child.stdout.on("data", data=>{
console.log(data.toString());
});
child.stderr.on("data", data=>{
console.log(data.toString());
});
child.on("exit", code=>{
console.log("Child exited with code "+code);
});
The python file:
from time import sleep
while True:
sleep(3)
print("test")
Edit: It works when using a nodejs script instead of a python script
change python script to
import time
import sys
while True:
time.sleep(1)
print("test")
sys.stdout.flush()
and increase the buffer size of the child process
const child = execFile("python", ["./runner.py"], {
detached: true,
maxBuffer: 10 * 1024 * 1024 * 1024
});
or you can do it without the flushing to stdout with python-shell
const { PythonShell } = require('python-shell');
let pyshell = new PythonShell('runner.py');
pyshell.on('message', function (message) {
console.log(message);
});
pyshell.end(function (err, code, signal) {
if (err) throw err;
console.log('The exit code was: ' + code);
console.log('The exit signal was: ' + signal);
console.log('finished');
});
Use spawn instead of execFile, dont forget options shell and stdio.
const spawn = require("child_process").spawn;
const child = spawn("python3", ["file.py"], {shell: true, stdio: 'inherit'});
child.on('data', function(data) {
console.log(data);
});
child.on('close', function(code) {
console.log('Child process exited with exit code '+code);
});
You can also add cwd option.
Was trying to implement something similar inside a NextJS application and wanted live output from my python script and using python-shell had the same issue that it was only giving me output when the process existed and I ended up using node-pty instead which worked as expected:
import { spawn } from "node-pty"
const pyProcess = spawn("python", ["path/to/python/script"], {
name: 'xterm-color',
cols: 80,
rows: 30,
cwd: process.cwd(),
});
pyProcess.on('data', function (data: { toString: () => any; }) {
console.log(data.toString());
});
pyProcess.on('exit', (code: any) => {
console.log(`child process exited with code ${code}`);
});

explorer.exe doesn't open correct folder when ran programmatically inside WSL

I'm trying to open explorer.exe from a Node.js script running inside WSL Ubuntu 20.04. The issue I've encountered is that explorer.exe never opens the folder I'd like it to. Instead of WSL user's home directory it opens my Windows user's Documents folder. What should I do to make explorer.exe open the folder I want?
Here's what I've tried:
The script first defines a function execShellCommand that promisifies exec. Then self-executing function first converts process.env.HOME to a Windows path with wslpath. Then it executes explorer.exe with the converted path as a parameter.
#!/usr/bin/node
const execShellCommand = async cmd => {
const exec = require('child_process').exec
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.warn(error)
}
resolve(stderr ? stderr : stdout)
})
})
}
;(async () => {
const path = await execShellCommand(`wslpath -w "${process.env.HOME}"`)
console.log({ path })
await execShellCommand(`explorer.exe ${path}`)
})()
The output I get when I run my script in WSL
$ ./script.js
{ path: '\\\\wsl$\\Ubuntu-20.04\\home\\user\n' }
Error: Command failed: explorer.exe \\wsl$\Ubuntu-20.04\home\user
at ChildProcess.exithandler (child_process.js:308:12)
at ChildProcess.emit (events.js:315:20)
at maybeClose (internal/child_process.js:1048:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:288:5) {
killed: false,
code: 1,
signal: null,
cmd: 'explorer.exe \\\\wsl$\\Ubuntu-20.04\\home\\user\n'
}
explorer.exe does run regardless of the error shown in the output. The weird part is that if I run the same command my script tries to run (explorer.exe \\\\wsl$\\Ubuntu-20.04\\home\\user\n) directly in WSL terminal explorer.exe does open the folder I want it to. Trimming the new line at the end of the path doesn't help.
I think you have to do some additional escaping on the backslashes that are produced by wslpath. The code below works for me, meaning it opens the correct directory in Windows Explorer.
Note: it does still throw the error you mentioned, which I think is due to the way node exits rather than anything wrong w/the execution of explorer.exe; I'm not a node expert by any stretch.
#!/usr/bin/node
const execShellCommand = async cmd => {
const exec = require('child_process').exec
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.warn(error)
}
resolve(stderr ? stderr : stdout)
})
})
}
;(async () => {
let path = await execShellCommand(`wslpath -w "${process.env.HOME}"`)
console.log("before", {path});
path = path.replace(/\\/g,"\\\\");
console.log("after", {path});
await execShellCommand(`explorer.exe ${path}`)
})()
Even cleaner than replacing backslashes, I think this will work for you by resolving the $HOME variable directly into your command line:
await execShellCommand(`explorer.exe "$(wslpath -w $HOME)"`);

How to serve yarn build file with npm serve command?

Basically, my task is to compile a js file and serve it at http://localhost:5000/final.js
I have the following script.
Current issues
The console.log seems printing out of order.
Able to switch dir and run yarn build, but it seems not able to serve file
Here is the source code:
#!/usr/bin/env node
const frontendDir =
"/my/frontend";
const jsDir =
"/my/frontend/build/static/js";
// util
const util = require("util");
// exec
const exec = util.promisify(require("child_process").exec);
// async func
async function runcmd(cmd) {
try {
const { stdout, stderr } = await exec(cmd);
// need output
console.log("stdout:", stdout);
// need error
console.log("stderr:", stderr);
} catch (err) {
console.error(err);
}
}
try {
// go to front end dir
process.chdir(frontendDir);
console.log("Switch to dir: " + process.cwd());
// yarn build
runcmd("yarn build");
// go to file dir
process.chdir(jsDir);
console.log("Switch to dir: " + process.cwd());
// find that js file and copy it, rename it
runcmd("cp main.*.js final.js");
// serve at /my/frontend/build/static/js with url http://localhost:5000/final.js
runcmd("serve .");
} catch (err) {
console.log("chdir: " + err);
}
Here is the output from the script above
Switch to dir: /my/frontend
Switch to dir: /my/frontend/build/static/js
stdout:
stderr:
stdout: yarn run v1.21.1
$ react-app-rewired build && cpr ./build/ ../build/frontend/ -o
Creating an optimized production build...
Compiled successfully.
File sizes after gzip:
210.3 KB build/static/js/main.c1e6b0e9.js
The project was built assuming it is hosted at ./.
You can control this with the homepage field in your package.json.
The build folder is ready to be deployed.
Find out more about deployment here:
Done in 13.91s.
stderr:
// https://stackoverflow.com/questions/41037042/nodejs-wait-for-exec-in-function
const exec = require("child_process").exec;
function os_func() {
this.execCommand = function(cmd) {
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
resolve(stdout);
});
});
};
}
const os = new os_func();
process.chdir(frontendDir);
os.execCommand("yarn buildlocal")
.then(() => {
console.log("# done yarn build");
process.chdir(jsDir);
os.execCommand("cp main.*.js docman.js").then(() => {
console.log("# done copy and serve at port 5000");
os.execCommand("serve -l 5000 .").then(() => {});
});
})
.catch(err => {
console.log("os >>>", err);
});

Cannot kill a linux process using node js process.kill(pid)

Im trying to kill background running process using nodejs process.kill(pid, 'SIGTERM'), but the process is not getting killed.
I executed node script mentioned below and later checked the process using ps -efww | grep 19783 | grep -v grep from the prompt to confirm it is still not killed.
I can confirm that the process it is trying to kill is started by the same user, so there is no permission issue.
Is there something I need to pass to get the process killed.
Node Version: 8.11.1
OS: Linux 3.10.0-327.10.1.e17.x86_64
Reference : Node process
Code :
'use strict';
const argv = require('yargs').argv;
const exec = require('child_process').exec;
function execute(command) {
console.log("Executing Command : ", command);
return new Promise((resolve, reject) => {
exec(command, {
maxBuffer: 1024 * 5000000
}, (error, stdout, stderr) => {
if (error) {
console.log(`ERROR: Something went wrong while executing ${command}: ${error}`);
reject(error);
} else {
resolve(stdout);
}
});
});
}
function kill(pid) {
try {
console.log(`Killing Process : ${pid}`);
process.kill(pid, 'SIGTERM');
let command = `ps -efww | grep ${pid} | grep -v grep | grep -v dzdo `;
let output = execute(command).then(res => {
console.log(`output: ${res}`);
}).catch(err => console.log(err));
} catch (e) {
console.log(`Invalid Process ID:${pid}, failed during kill, "ERROR: ${e}"`);
}
}
function main() {
// remove all spaces;
if (argv.kill) {
let allPIDs = argv.kill || undefined;
// console.log(`ALL PID's: ${allPIDs}`);
allPIDs = allPIDs.toString().replace(/\s/, '').split(',');
if (allPIDs.length > 0) {
allPIDs.forEach(pid => {
if (!isNaN(pid)) {
// console.log(`Valid PID: ${pid}`);
kill(pid);
} else {
console.log(`ERROR: Invalid Process ID : ${pid}, Skipped Kill `);
}
});
}
}
}
main();
Assuming this code is saved as killer.js
Usage: node killer.js --kill=19783
Try SIGKILL instead of SIGTERM
The doc says
'SIGKILL' cannot have a listener installed, it will unconditionally terminate Node.js on all platforms.
So I think worth trying.

Categories