Using child_process (spawn) to open a new BASH terminal and execute the commands in each file.
I want to add all of my .sh files, that I'm going to spawn, into a folder to clean up my project directory.
PROBLEM:
I can't figure out how to change the directory the scripts run from, and the docs are a little to heavy for me at this point.
SIMPLE TEST EXAMPLE, WITH MY FIRST TWO FILES FOR CONNECTING (each .sh file would be in the project folder):
const { spawn } = require('node:child_process');
const bat = spawn('cmd.exe', ['/c', 'connect.sh']);
/*
<connect.sh> // 1st .sh file
#!/usr/bin/env bash //to make it bash
HTTP_PORT=3002 P2P_PORT=5002 PEERS=ws://localhost:5001 npm run dev
<connect1.sh> // 2nd .sh file
#!/usr/bin/env bash //to make it bash
HTTP_PORT=3003 P2P_PORT=5003 PEERS=ws://localhost:5002,ws://localhost:5001 npm run dev
*/
I have 9 of these files to connect up to 10 peers. And I would like to put them in a folder to simplify my project structure.
This is my actual API call below....
// Uses length to determine which file to run
app.post("/peers/connect", async function (req, res) {
const peerInfo = await peers.info();
// no peers yet
if (typeof peerInfo === "string") {
let bat = spawn("cmd.exe", ["/c", "connect.sh"]);
res.json("A new terminal has opened! You are now connected!");
} else {
// peers exist
let length = peerInfo.peers;
// console.log(length);
let bat = spawn("cmd.exe", ["/c", `connect${length}.sh`]);
res.json("A new terminal has opened! You are now connected!");
}
});
My file structure here...you can see why I want a folder for these!
RECAP:
Help my put all of these files into a folder (shellScripts) and have the code still work :)
Thanks! (just realized we might have to cd back into project folder before "npm run dev" in each file?)
You are using the cmd.exe utility to run a .sh file, but that wont work. You have to install a bash interpreter on your windows device or install WSL. (If necessary add bash.exe to the windows path) Then change your code to this:
const { spawn } = require('node:child_process');
const bat = spawn('bash.exe',['connect.sh']);
I hope this answer helped
For running multiple files:
const { spawn } = require('node:child_process');
const fs = require("node:fs")
const dir = "" // Replace this with the location of the directory containing connect shellscripts
let entrys = fs.readdirSync(dir)
entrys = entrys.filter(v => v.startsWith("connect"))
for (let ent of entrys) {
const bat = spawn('bash.exe',[ent]);
// your code here
}
Figured out the answer on me own. Thanks to everyone that tried to help :)
And to those saying my above code doesn't work, it works perfectly fine.
I've provided a picture to clarify. 1st is what the code below produces. 2nd is manually pasting it into GIT BASH.
// test.js in project structure pic above
var exec = require('child_process').exec;
var path = require('path')
var parentDir = path.resolve(process.cwd(), 'shellScripts');
exec('my.sh', {cwd: parentDir}, function (error, stdout, stderr) {
// if you also want to change current process working directory:
process.chdir(parentDir);
});
This is what the code produces.
And this is opening a GIT BASH in project folder and pasting the command in
Related
So I followed the dynamic command handler guide on the discord.js guide site, and it turns out every time I try to let it execute a command, it says that the execute function is undefined, no matter how I tried to fix it. To make sure that my code is supposed to be working, I downloaded the example code they had on the guide and ran it, which also didn’t work for some reason. My discord.js and node.js are all up to date.
Since I do not know your current files/code, I can provide an example.
Also, in this example, I will be assuming that you have named your bot variable client.
First, make sure you have a folder named commands.
On the top of your bot code (index.js or whatever it's called), add this line:
const fs = require("fs");
In your bot code, after the bot definition (var client = new Discord.Client()), add these lines:
client.commands = new Discord.Collection();
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
for(let file of commandFiles) {
let command = require('./commands/' + file);
client.commands.set(command.name, command);
}
And on your message event listener (assuming that you already have made some commands in the folder), replace your command if statement(s) with this:
// you can use other expressions to check if the command is there
// the commandname in the client.commands.get is the filename without .js
if(message.content.startsWith("commandname")) client.commands.get("commandname").execute(message, args);
Creating commands will be the process of creating JavaScript files in your commands folder. So in your commands folder, create a file (filename will be like "commandname.js" or something) and the content will be:
module.exports = {
name: "commandname",
description: "Command description here.",
execute(message, args) {
// Now you can do your command logic here
}
}
I hope this helped! If it isn't clear, feel free to downvote.
When using .js files that are run with Windows Script Host, is it possible to get the path of the .js file that is running (which is not the same as the current working directory)? In other words, I'm wanting something similar to PowerShell's $PSScriptRoot variable. Is there any way to get this?
The reason I want this is because the working directory when these scripts are executed is not always the same as the location of the .js file itself, but I want my code to reference things relative to the location of the .js file.
You can get this with Node Js
const path = require('path'); // you can install this with npm
// __dirname = C:\dev\project
// __filename = C:\dev\project\index.js
const dir= path.basename(__dirname);
const archive= path.basename(__filename);
const fullpath = path.join(dir, archive);
console.log('Dir:', dir); // Dir: test
console.log('Archive:', archive); // Archive: index.js
console.log('Dir + Archive:', fullpath); // Dir + Archive: project\index.js
I have written the following code in app.js for Windows
app.js
app.route('/file').post(function (req,res,next) {
// The path to your python script
var myPythonScript = "script.py";
// Provide the path of the python executable, if python is available as environment variable then you can use only "python"
var path =resolve("C:\\Python27\\python.exe");
var pythonExecutable = path;
var macadd =req.body.macadd;
var percent =req.body.percent;
// Function to convert an Uint8Array to a string
var uint8arrayToString = function(data){
return String.fromCharCode.apply(null, data);
};
const spawn = require('child_process').spawn;
const scriptExecution = spawn(pythonExecutable, [myPythonScript]);
// Handle normal output
scriptExecution.stdout.on('data', (data) => {
console.log(String.fromCharCode.apply(null, data));
});
var data = JSON.stringify([1,2,3,4,5]);
scriptExecution.stdin.write(data);
// End data write
scriptExecution.stdin.end();
});
As you can see the path for the python executable file is provided. This code works properly in Windows and gives the summation of the number in the array on the console. I want to execute the same code in Ubuntu. What do I specify for the python executable path in Linux(Ubuntu)?
That will depend on where is the python executable in your Linux setup.
As you said it's an Ubuntu (no version specified), you can try just using python without a path, as the python executable should be already in the PATH and usually it comes installed with your distribution.
If that doesn't work, you can figure out the python executable path running which python on the Linux shell.
And lastly, you can also try /usr/bin/python for the executable path, as it's the usual location for it.
You can use process.platform to get the current platform.
For example on my mac I have process.platform === 'darwin'.
documentation
How can I get the absolute path of a directory (not the current working directory) in node webkit application?
Example (Mac OS) - I have created a folder named A in my Documents. When I do getDirectory with file system directory entry, I can only get dir.fullPath which returns A
app.workspace.getDirectory(self.folderpath, {}, function(dir){
if(dir) console.log('Dir: ', dir);
});
But I need: ~/Documents/A/ || c:\Users\Username\Documents
In my app users can choose/create a directory where ever they want and I store/read data from that folder.
Absolute path may not be what I need but I want to open files (PDF, doc...) with default desktop applications:
function getCommandLine() {
switch (process.platform) {
case 'darwin' : return 'open';
case 'win32' : return 'start';
case 'win64' : return 'start';
default : return 'xdg-open';
}
}
var exec = require('child_process').exec;
var filepath = '...';
//dir.fullPath will throw: The file /A/example.pdf does not exist.
var child = exec(getCommandLine() + ' ' + filepath, function (error, stdout, stderr) {
if (error) {
console.error(`exec error: ${error}`);
return;
}
});
child.on('close', function (e) {
console.log('E: ', e);
});
You cannot access the absolute path of a system's directory-file-everything from a web page for security reasons. Even if you try to access a specific file directory from a javascript script (for example), the browser will immediately block you.
A solution that might work for you is to retrieve the file that the user wants to open with a simple <input type="file">, so that the user can select a file without giving to you its absolute path;after that you can save the file onto a server-host, or even the project's local directory, and then use the remote path to open it with the exec command.
Not sure I've understood thequestion. You can user __dirname to get the directory of the script you are executing. See: https://nodejs.org/docs/latest/api/globals.html#globals_dirname
And from there you can use relative paths to reference other files and folders.
Example folder structure:
/home/filippo/works/test/
├── subfolder
│ └── index.js
└── test.js
subfolder/index.js:
module.exports = {'folder': __dirname};
test.js:
var m = require("./subfolder/");
console.log("test.js running in: ", __dirname);
console.log("m module running in: ", m.folder);
Running the test:
$ node test.js
test.js running in: /home/filippo/works/test
m module running in: /home/filippo/works/test/subfolder
Is this what you are looking for?
Actually I recently found out (I can't believe I missed it out in the first place but), with chrome file system you can get "more readable" path info for display purposes.
Depending on what you are trying to do, you might not access the absolute location but at least you can see what it is...
fileSystem.getDirectory(path, {}, function(dir){
if(dir) console.log('This should return full path: ', dir.getDisplayPath());
var fullpath = dir.getDisplayPath();
//now with this, I can open any file I want via child process :)
var child = exec(getCommandLine() + ' ' + fullpath, function (error, stdout, stderr)
//.......
});
More info here regarding chrome file system.
I'm using Grunt to kick off a unit-test framework (Intern), which ultimately pipes another node.js process that I'm then using Charm to output results to the screen. I'm having to pass in the terminal size information from a Grunt config option, but it's a bit messy and I'd like to try and get the terminal size from within the piped process, but the standard process.stdout.cols/getWindowSize are simply unavailable as the piped process doesn't register as TTY (although Charm works fine with it all).
Any suggestions?
EDIT Just to be clear here ... the Grunt JavaScript file is running in the main node.js process, but the file I'm attempting to retrieve this info from (and where I'm therefore running people's suggested commands) is in a spawned child process.
Try these:
tput cols tells you the number of columns.
tput lines tells you the number of rows.
echo -e "lines\ncols"|tput -S to get both the lines and cols
There's stty, from coreutils:
$ stty size #60 120 <= sample output
While running the below code in terminal prints the cols:
var sys = require('sys')
var exec = require('child_process').exec;
function puts(error, stdout, stderr) { sys.puts(stdout) }
exec("tput cols", puts);
The pty.js module can make a child act like a regular terminal.
var pty = require('pty.js');
var term = pty.spawn('bash', [], {
name: 'xterm-color',
cwd: process.env.HOME,
env: process.env
});
term.on('data', function(data) {
console.log(data);
});
term.write('ls\r');
term.resize(100, 40);
term.write('ls /\r');
console.log(term.process);