I tried to run a nodejs script with the built in child_process module and it works fine until i give it options. Specially when i add the env property to the options object.
let exec = require('child_process').exec;
exec('node random.js', { env: {} }, (err) => {
console.log(err);
})
Then i get this error: /bin/sh: 1: node: not found.
I have node installed with nvm, maybe that is the cause, but don't know why.
If you exec a new shell from your script this don't have the same environment of the parent shell (your script).
So you have to provide all the needed environment.
In your case I see 2 way you could do.
First: you create a node command with the full path:
let exec = require('child_process').exec;
let node_cmd = '/path/to/my/node/node';
exec(node_cmd + ' random.js', { env: {} }, (err) => {
console.log(err);
});
So you could use env variables to handle the path, or just change it when you need.
Second, pass the path variable to the command:
let exec = require('child_process').exec;
let env_variables = 'PATH='+process.env.PATH;
let cmd = env_variables + ' node random.js';
exec(cmd, { env: {} }, (err) => {
console.log(err);
});
Another way is using the dotenv package.
Related
I'm trying to run a discord bot that I found on GitHub. I use Windows, the program uses Docker, Node, and maybe some other things I'm not aware of.
When I run the program with "node start-bots.js", cmd gives me an error:
'BOT' is not recognized as an internal command or external command, an executable program or a command file.
I tried many things but nothing works...
Here is the code of the start-bot.js :
const exec = require('child_process').exec;
const bots = require('./bots.json');
const recreate = () => {
console.log(`🐳 Checking existing volumes...`);
exec(`docker volume ls -q`, (err, stdout, stderr) => {
const volumes = stdout.split('\n');
bots.forEach((bot) => {
console.log(`🐋 Starting ${bot.name}...`);
const start = () => {
exec(`BOT=${bot.name} VINTED_BOT_ADMIN_IDS=${bot.adminIDs}
VINTED_BOT_TOKEN=${bot.token} docker-compose -f docker-compose.yaml -p
bot-${bot.name} up -d`, (err, stdout, stderr) => {
if (err) {
console.error(`🐋 ${bot.name} failed to start.`);
console.error(err);
return;
}
console.log(stderr);
});
}
if (volumes.includes(`bot-${bot.name}`)) {
console.log(`📦 ${bot.name} database has been recovered!`);
start();
} else {
exec(`docker volume create bot-${bot.name}`, (err, stdout, stderr) => {
if (!err) {
console.log(`📦 ${bot.name} database has been created!`);
start();
} else console.error(err);
});
}
});
});
};
const restart = process.argv.includes('-restart');
if (restart) {
console.log('👋 Shutting down all bots...');
bots.forEach((bot) => {
exec(`docker-compose -p bot-${bot.name} stop`, (err, stdout, stderr) => {
if (!err) {
exec(`docker-compose -p bot-${bot.name} rm -f`, (err, stdout, stderr) => {
if (!err) {
console.log(`👋 Bot ${bot.name} has been shut down and
removed.`);
} else {
console.log(`👎 Failed to remove containers for bot
${bot.name}`);
}
});
}
});
});
} else {
recreate();
}
and and docker-compose.yaml :
version: '3.8'
services:
vinted-discord-bot:
image: vinted-discord-bot:3.17
environment:
VINTED_BOT_ADMIN_IDS: "${VINTED_BOT_ADMIN_IDS}"
VINTED_BOT_TOKEN: "${VINTED_BOT_TOKEN}"
POSTGRES_DB: vinted_bot
POSTGRES_USER: root
POSTGRES_PASSWORD: password
restart: always
depends_on:
- postgres
postgres:
image: postgres:14.1
healthcheck:
test: [ "CMD", "pg_isready", "-q", "-d", "postgres", "-U", "root" ]
timeout: 45s
interval: 10s
retries: 10
restart: always
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: password
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
external:
name: bot-${BOT}
and finally the bots.json :
[
{
"name": "thenameofthebot",
"token": "thetokenofthebot",
"adminIDs": "theidoftheadminserver"
}
]
Here is a screen of the error (in French):
You can find it on: https://github.com/Androz2091/vinted-discord-bot.
You need to make a binary for your program. In Node.js, you can create a binary in package.json.
Step 1: In your main file, you need to add a shebang (#!), and /usr/bin/env node after that. Important! This must be on the very first line of your main file.
#!/usr/bin/env node
Step 2: In your package.json file, add the following two keys, replacing index.js with your own main file.
{
"main": "index.js",
"bin": {
"BOT": "./index.js"
},
}
Step 3: Run the following command to apply it to your computer.
npm link
EDIT: If the above command doesn't work, run the following command.
npm install -g .
And that's it! It should work when you run the following command.
BOT
I've created a webpack configuration file that builds the app, runs a dev server using webpack-dev-server and runs the test suite as below.
devServer: {
contentBase: path.join(__dirname, "dist"),
port: 3000,
watchOptions: {
open: false
},
historyApiFallback: {
index: "/"
}
},
plugins: [
new WebpackShellPlugin({
onBuildEnd: [`./node_modules/.bin/cucumber-js ${testScope}`]
})
]
The command to start the whole thing is below
webpack-dev-server --config webpack.test.js
Everything is ok, but... what now? It never stops! I need some way to exit with a successful status when the test suite is ok. Otherwise, it would cause an infinite deploy (I use bitbucket pipelines to deploy the app).
Does someone know a way to exit the devServer execution after running a specific plugin?
Likely it is the difference between npm run start and npm start
When you use npm start, it runs node server.js which doesn't run inline with your console.
If you use npm run start, it executes the start script defined in your package.json using the shell of your operating system. Therefore, even if you are using Cygwin (or similar), it should still run it using cmd.exe.
Solution
Use npm run start instead of npm start and it should kill the process when you CTRL + C
I solved my own problem by creating a webpack plugin and added it to my config file. The plugin code is below. It runs the command I pass to it and exit the process, firing error if the command was successful or success if it was everything ok.
const spawn = require("child_process").spawn;
module.exports = class RunScriptAndExit {
constructor(command) {
this.command = command;
}
apply(compiler) {
compiler.plugin("after-emit", (compilation, callback) => {
const { command, args } = this.serializeScript(this.command);
const proc = spawn(command, args, { stdio: "inherit" });
proc.on("close", this.exit);
callback();
});
}
serializeScript(script) {
if (typeof script === "string") {
const [command, ...args] = script.split(" ");
return { command, args };
}
const { command, args } = script;
return { command, args };
}
exit(error, stdout, stderr) {
if (error) {
process.exit(1);
} else {
process.exit(0);
}
}
};
I added it to my plugin list as below:
plugins: [
new RunScriptAndExit(`./node_modules/.bin/cucumber-js ${testScope}`)
]
I need a complete guide or a good reference material to solve the running module commands within javascript file problem.
Say that I often run:
$ npm run webpack-dev-server --progress --colors -- files
How can I run this within a javascript file and execute with
$ node ./script.js
script.js
var webpackDevServer = require('webpack-dev-server');
// need help here
var result = webpackDevServer.execute({
progress: true,
colors: true,
}, files);
Answer
I do something like this for my Webpack bundles. You can simply use child_process.spawn to execute command-line programs and handle the process in a node script.
Here's an example:
var spawn = require('child_process').spawn
// ...
// Notice how your arguments are in an array of strings
var child = spawn('./node_modules/.bin/webpack-dev-server', [
'--progress',
'--colors',
'<YOUR ENTRY FILE>'
]);
child.stdout.on('data', function (data) {
process.stdout.write(data);
});
child.stderr.on('data', function (data) {
process.stdout.write(data);
});
child.on('exit', function (data) {
process.stdout.write('I\'m done!');
});
You can handle all of the events you like. This is a fairly powerful module that allows you to view the process' PID (child.pid) and even kill the process whenever you choose (child.kill()).
Addendum
A neat trick is to throw everything into a Promise. Here's a simplified example of what my version of script.js would look like:
module.exports = function () {
return new Promise(function (resolve, reject) {
var child = spawn('./node_modules/.bin/webpack', [
'-d'
]);
child.stdout.on('data', function (data) {
process.stdout.write(data);
});
child.on('error', function (data) {
reject('Webpack errored!');
});
child.on('exit', function () {
resolve('Webpack completed successfully');
});
});
}
Using this method, you can include your script.js in other files and make this code synchronous in your build system or whatever. The possibilities are endless!
Edit The child_process.exec also lets you execute command-line programs:
var exec = require('child_process').exec
// ...
var child = exec('webpack-dev-server --progress --colors <YOUR ENTRY FILES>',
function(err, stdout, stderr) {
if (err) throw err;
else console.log(stdout);
});
The accepted answer doesn't work on Windows and doesn't handle exit codes, so here's a fully featured and more concise version.
const spawn = require('child_process').spawn
const path = require('path')
function webpackDevServer() {
return new Promise((resolve, reject) => {
let child = spawn(
path.resolve('./node_modules/.bin/webpack-dev-server'),
[ '--progress', '--colors' ],
{ shell: true, stdio: 'inherit' }
)
child.on('error', reject)
child.on('exit', (code) => code === 0 ? resolve() : reject(code))
})
}
path.resolve() properly formats the path to the script, regardless of the host OS.
The last parameter to spawn() does two things. shell: true uses the shell, which appends .cmd on Windows, if necessary and stdio: 'inherit' passes through stdout and stderr, so you don't have to do it yourself.
Also, the exit code is important, especially when running linters and whatnot, so anything other than 0 gets rejected, just like in shell scripts.
Lastly, the error event occurs when the command fails to execute. When using the shell, the error is unfortunately always empty (undefined).
Do you need it to be webpack-dev-server? There is an equivalent webpack-dev-middleware for running within node/express:
'use strict';
let express = require('express');
let app = new express();
app.use(express.static(`${__dirname}/public`));
let webpackMiddleware = require('webpack-dev-middleware');
let webpack = require('webpack');
let webpackConfig = require('./webpack.config.js');
app.use(webpackMiddleware(webpack(webpackConfig), {}));
app.listen(3000, () => console.log(`Server running on port 3000...`));
https://github.com/webpack/webpack-dev-middleware
I don't know how to execute an exe file in node.js. Here is the code I am using. It is not working and doesn't print anything. Is there any possible way to execute an exe file using the command line?
var fun = function() {
console.log("rrrr");
exec('CALL hai.exe', function(err, data) {
console.log(err)
console.log(data.toString());
});
}
fun();
you can try execFile function of child process modules in node.js
Refer:
http://nodejs.org/api/child_process.html#child_process_child_process_execfile_file_args_options_callback
You code should look something like:
var exec = require('child_process').execFile;
var fun =function(){
console.log("fun() start");
exec('HelloJithin.exe', function(err, data) {
console.log(err)
console.log(data.toString());
});
}
fun();
If the exe that you want to execute is in some other directory, and your exe has some dependencies to the folder it resides then, try setting the cwd parameter in options
var exec = require('child_process').execFile;
/**
* Function to execute exe
* #param {string} fileName The name of the executable file to run.
* #param {string[]} params List of string arguments.
* #param {string} path Current working directory of the child process.
*/
function execute(fileName, params, path) {
let promise = new Promise((resolve, reject) => {
exec(fileName, params, { cwd: path }, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
return promise;
}
Docs
If you are using Node Js or any front end framework that supports Node JS (React or Vue)
const { execFile } = require('child_process');
const child = execFile('chrome.exe', [], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout);
});
If the .exe file is located somewhere in the machine, replace chrome.exe with the path to the application you want to execute
e.g "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
const child = execFile('C:\Program Files (x86)\Google\Chrome\Application\chrome.exe', [], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout);
});
Did you ever think about using Batch file in this process? I mean start a .bat file using node.js which will start an .exe file in the same time?
just using answers in the top i got this:
Creating a .bat file in exe file's directory
Type in bat file
START <full file name like E:\\Your folder\\Your file.exe>
Type in your .js file:
const shell = require('shelljs')
shell.exec('E:\\Your folder\\Your bat file.bat')
I have a node / angular project that uses npm for backend dependency management and bower for frontend dependency management. I'd like to use a grunt task to do both install commands. I haven't been able to figure out how to do it.
I made an attempt using exec, but it doesn't actually install anything.
module.exports = function(grunt) {
grunt.registerTask('install', 'install the backend and frontend dependencies', function() {
// adapted from http://www.dzone.com/snippets/execute-unix-command-nodejs
var exec = require('child_process').exec,
sys = require('sys');
function puts(error, stdout, stderr) { console.log(stdout); sys.puts(stdout) }
// assuming this command is run from the root of the repo
exec('bower install', {cwd: './frontend'}, puts);
});
};
When I cd into frontend, open up node, and run this code from the console, this works fine. What am I doing wrong in the grunt task?
(I also tried to use the bower and npm APIs, but couldn't make that work either.)
To install client side components during npm install at the same time than server side libs, you can add in your package.json
"dependencies": {
...
"bower" : ""
},
"scripts": {
...
"postinstall" : "bower install"
}
I prefer to make the difference between install and test/build
You need to tell grunt that you're using an async method (.exec) by calling the this.async() method, getting a callback, and calling that when exec is done.
This should work:
module.exports = function(grunt) {
grunt.registerTask('install', 'install the backend and frontend dependencies', function() {
var exec = require('child_process').exec;
var cb = this.async();
exec('bower install', {cwd: './frontend'}, function(err, stdout, stderr) {
console.log(stdout);
cb();
});
});
};
See Why doesn't my asynchronous task complete?
FYI, here is where i am for now.
You could also have taken the problem another way, i.e. let npm handle the execution of bower, and ultimately let grunt handle npm. See Use bower with heroku.
grunt.registerTask('install', 'install the backend and frontend dependencies', function() {
var async = require('async');
var exec = require('child_process').exec;
var done = this.async();
var runCmd = function(item, callback) {
process.stdout.write('running "' + item + '"...\n');
var cmd = exec(item);
cmd.stdout.on('data', function (data) {
grunt.log.writeln(data);
});
cmd.stderr.on('data', function (data) {
grunt.log.errorlns(data);
});
cmd.on('exit', function (code) {
if (code !== 0) throw new Error(item + ' failed');
grunt.log.writeln('done\n');
callback();
});
};
async.series({
npm: function(callback){
runCmd('npm install', callback);
},
bower: function(callback){
runCmd('bower install', callback);
}
},
function(err, results) {
if (err) done(false);
done();
});
});
Grunt task that does just this job (as per Sindre's solution above):
https://github.com/ahutchings/grunt-install-dependencies
Grunt task that does the bower install command :
https://github.com/yatskevich/grunt-bower-task
also , you can use
https://github.com/stephenplusplus/grunt-bower-install
to auto inject your dependencies into the index.html file