Spawning child process in python in Node JS - javascript

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

Related

Arguments for Node child_process "spawn()"

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

Running a Python script with exec node then parsing to javascript with function node in Node red

I have a python script that controls a vibration sensor connected to my raspberry pi. I have that python script in the exec node. I need to parse the python code into javascript using the function node. (I'm doing this in node-red on the raspberry pi).
The JavaScript code I'm running does not return the value I need from the python code. I need the variable "sensor" to return in the javascript code.
python code:
import time
import RPi.GPIO as GPIO
vibe = 4
GPIO.setmode(GPIO.BCM)
GPIO.setup(vibe, GPIO.IN)
def callback(Vibe):
if GPIO.input(vibe):
sensor = "vibration"
print(sensor)
else:
print("error")
GPIO.add_event_detect(vibe, GPIO.BOTH, bouncetime=300)
GPIO.add_event_callback(vibe, callback)
while True:
time.sleep(1)
GPIO.cleanup()
javascript code:
var vibrationSensor = msg.payload;
var sensor = str.substr(1,15);
msg.payload = {
"vibration": sensor,
};
return msg;
What it looks like in node-red:
Since the python code will never exit, you need to use the Daemon node rather than the exec node

How to run complex command in node js spawn?

I am developing a lib for docker command line in nodejs, I am still in starting face, I just tried basic docker run command using spawn in node js - everything works fine but it's not working for complex cases like the one below.
I want to run docker run --rm -it julia:0.3.6 julia -E "[x^2 for x in 1:100]" in nodejs, but I am gettting below error -
the input device is not a TTY
Docker Shell existed with status = 1
Below Code -
const
spawn = require('child_process').spawn,
dockerDeamon = spawn("docker", ["run","--rm", "-it", "julia:0.3.6", "-E", "\" [x^2 for x in 1:100]\""] );
dockerDeamon.stdout.on('data', data => {
console.log(`${data}`);
});
dockerDeamon.stderr.on('data', data => {
console.log(`${data}`);
});
dockerDeamon.on('close', code => {
console.log(`Docker Shell existed with status = ${code}`);
});
Is there any better way to execute the above script ?
You're passing the -t (--tty) flag to Docker, which tells it that it should expect the input and output to be attached to a terminal (TTY). However, when you're using spawn, you're instead attaching it to a Node.js stream in your program. Docker notices this and therefore gives the error Input device is not a TTY. Therefore, you shouldn't be using the -t flag in this case.
Also, note that you don't need nested quotes in your last argument, "\" [x^2 for x in 1:100]\"". The purpose of the quotes is to preserve the spaces and other special characters in the argument when running in a shell, but when you use spawn you're not using a shell.
So your statement should be something like:
dockerDeamon = spawn("docker", ["run","--rm", "-i", "julia:0.3.6", "julia", "-E", "[x^2 for x in 1:100]"] );

How can I get terminal size in a piped node.js process?

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);

Get directory of a file name in Javascript

How to get the directory of a file?
For example, I pass in a string
C:\Program Files\nant\bin\nant.exe
I want a function that returns me
C:\Program Files\nant\bin
I would prefer a built in function that does the job, instead of having manually split the string and exclude the last one.
Edit: I am running on Windows
I don't know if there is any built in functionality for this, but it's pretty straight forward to get the path.
path = path.substring(0,path.lastIndexOf("\\")+1);
If you use Node.js, path module is quite handy.
path.dirname("/home/workspace/filename.txt") // '/home/workspace/'
Use:
var dirname = filename.match(/(.*)[\/\\]/)[1]||'';
*The answers that are based on lastIndexOf('/') or lastIndexOf('\') are error prone, because path can be "c:\aa/bb\cc/dd".
(Matthew Flaschen did took this into account, so my answer is a regex alternative)
There's no perfect solution, because this functionality isn't built-in, and there's no way to get the system file-separator. You can try:
path = path.substring(0, Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")));
alert(path);
Path module has an inbuilt function
Yes, the inbuilt module path has dirname() function, which would do the job for you.
const path = require("path");
file_path = "C:\\Program Files\\nant\\bin\\nant.exe" \\windows path
file_path = "C:/Program Files/nant/bin/nant.exe" \\linux path
path.dirname(file_path); \\gets you the folder path based on your OS
I see that your path is neither windows nor Linux compatible. Do not hardcode path; instead, take a reference from a path based on your OS.
I generally tackle such situations by creating relative paths using path.join(__dirname, "..", "assets", "banner.json");.
This gives me a relative path that works regardless of the OS you are using.
function getFileDirectory(filePath) {
if (filePath.indexOf("/") == -1) { // windows
return filePath.substring(0, filePath.lastIndexOf('\\'));
}
else { // unix
return filePath.substring(0, filePath.lastIndexOf('/'));
}
}
console.assert(getFileDirectory('C:\\Program Files\\nant\\bin\\nant.exe') === 'C:\\Program Files\\nant\\bin');
console.assert(getFileDirectory('/usr/bin/nant') === '/usr/bin');
Sorry to bring this back up but was also looking for a solution without referencing the variable twice. I came up with the following:
var filepath = 'C:\\Program Files\\nant\\bin\\nant.exe';
// C:\Program Files\nant\bin\nant.exe
var dirpath = filepath.split('\\').reverse().splice(1).reverse().join('\\');
// C:\Program Files\nant\bin
This is a bit of a walk through manipulating a string to array and back but it's clean enough I think.
filepath.split("/").slice(0,-1).join("/"); // get dir of filepath
split string into array delimited by "/"
drop the last element of the array (which would be the file name + extension)
join the array w/ "/" to generate the directory path
such that
"/path/to/test.js".split("/").slice(0,-1).join("/") == "/path/to"
And this?
If isn't a program in addressFile, return addressFile
function(addressFile) {
var pos = addressFile.lastIndexOf("/");
pos = pos != -1 ? pos : addressFile.lastIndexOf("\\");
if (pos > addressFile.lastIndexOf(".")) {
return addressFile;
}
return addressFile.substring(
0,
pos+1
);
}
console.assert(getFileDirectory('C:\\Program Files\\nant\\bin\\nant.exe') === 'C:\\Program Files\\nant\\bin\\');
console.assert(getFileDirectory('/usr/bin/nant') === '/usr/bin/nant/');
console.assert(getFileDirectory('/usr/thisfolderhaveadot.inhere') === '/usr/');
The core Javascript language doesn't provide file/io functions. However if you're working in a Windows OS you can use the FileSystemObject (ActiveX/COM).
Note: Don't use this in the client script-side script of a web application though, it's best in other areas such as in Windows script host, or the server side of a web app where you have more control over the platform.
This page provides a good tutorial on how to do this.
Here's a rough example to do what you want:
var fso, targetFilePath,fileObj,folderObj;
fso = new ActiveXObject("Scripting.FileSystemObject");
fileObj = fso.GetFile(targetFilePath);
folderObj=fileObj.ParentFolder;
alert(folderObj.Path);

Categories

Resources