I am wanting to make a function that receives a String that is the input and returns me an output as a string, but I am not able because of the response delay
var resultado = "old value";
function execShell(cmd) {
exec("uname", (error, data, getter) => {
if(error){
console.log("error",error.message);
return;
}
if(getter){
console.log("data",data);
return;
}
console.log(`need before exec: ${data}`);
resultado = data;
});
}
/* shell command for Linux */
execShell('uname');
console.log(`need after exec: ${resultado}`);
What happens here is, that that the callbacks are not executed from top to bottom. This means that console.log(need after exec: ${resultado}); is called directly after execShell and the child process hasn't returned yet.
You could use the sync version to execute it:
const cp = require("child_process");
const result = cp.execSync("uname").toString(); // the .toString() is here to convert from the buffer to a string
console.log(`result after exec ${result}`);
The docs are https://nodejs.org/dist/latest-v14.x/docs/api/child_process.html#child_process_child_process_execsync_command_options
You could use a NPM package that helps with the shell handling if that's what you are building: https://github.com/shelljs/shelljs which wraps alot of the child process parts with an easier API.
Related
I have a JavaScript file (file.js) that contains the following code:
console.log("Hello World!")
When I run this code in my terminal node file.js, I get the following output:
Hello World
If I wanted to save this to a file programmatically (not right clicking and clicking save), does anyone know how I can do that?
The only solution I can find on the internet was using JSON.stringify("Hello World!"), but this doesn't do anything I don't believe (doesn't even output an error).
Reference: How to save the output of a console.log(object) to a file?
You'll need to overwrite console.log with your own implementation that writes the values it's called with to a file.
const { appendFileSync } = require('fs');
const origConsole = globalThis.console;
const console = {
log: (...args) => {
appendFileSync('./logresults.txt', args.join('\n') + '\n');
return origConsole.log.apply(origConsole, args);
}
}
console.log("Hello World!");
console.log("another line", "yet another line");
If you called this frequently enough such that the sync writes are a problem, you could use appendFile or fs.promises.appendFile so that the writes don't block and use a queue for the pending values to write.
I suppose that your console.log() is some kind of text output you get from somewhere, so i made a randomstring gen function just to exemplify.
You just need to use the fs module from Node, then write the file to your system.
Like this:
const fs = require('fs');
const randomString = () => {
return Math.random().toString(36).substring(7);
};
const createFile = (fileName, content) => {
fs.writeFile(fileName, content, (err) => {
if (err) throw err;
console.log('The file has been saved!');
});
}
createFile('test.txt', randomString());
Just note that if you're receiving text from an iteration, you maybe wanna insert '\n' on the end of each iteration to break the line on your text file.
For a project I need to incorporate a backend Python function with Javascript (main code for a chatbot). Using Child processes, it seems to work (when using 'node script.js'). However, I need to access the data from the called python function. Right now, all I am getting is the the output.I tried to store it in the global variable, but it's showing as 'undefined'. Is there a way to actually access the data so I can use it outside the stdout.on?
This is the Javascript code for running the pythonscript:
// Give a path to the QR scanner Python file
const qrScannerPath = "python/qrCodeScanner.py"
const base64Arg = "base64_2.txt"
// Provide the '.exe' python file. If python is available as an 'environment varaible', then simply refer to it as 'python'"
const pythonExe = "python"
// Function to convert a utf-8 array to a string
const utfConverter = function (data) {
return String.fromCharCode.apply(String,(data))
}
// let's us handle python scripts
const spawn = require("child_process").spawn
const scriptExe = spawn(pythonExe, [qrScannerPath, base64Arg])
// If all goes well, the program should execute the Python code
let counterpartyData = {}
scriptExe.stdout.on("data", function (data) {
console.log("getting the Python script data...")
let cp = JSON.parse(utfConverter(data))
counterpartyData = {... cp} //should store the data to the variable
});
console.log(counterpartyData) // shows 'undefinied"
// In case our python script cannot be run, we'll get an error
scriptExe.stderr.on("data", (data) => {
console.error("error : " + data.toString())
});
//logs error message
scriptExe.on('error', (error) => {
console.error('error: ', error.message);
});
// Logs a message saying that our code worked perfectly fine
scriptExe.on("exit", (code) => {
console.log("Process quit with code : " + code)
})
If I run this code with node, the output of 'counterpartyData' is undefined. However, inside the stdout, it actually prints out the data I want.
Furthermore, I get python import errors when running the app on Heroku :(.
Thank you in advance!!
Happy New Year and joyful greetings <3
Here is my nodejs code:
const cp = require('child_process');
describe('cloud function test suites', () => {
describe('deleteCampaign test suites', () => {
const cloudFunctionName = 'deleteCampaign';
it('should print campaign data', () => {
const campaign = { id: '1' };
const encodedCampaign = Buffer.from(JSON.stringify(campaign)).toString(
'base64',
);
const data = JSON.stringify({ data: encodedCampaign });
const executeResultOutput = cp
.execSync(
`gcloud beta functions call ${cloudFunctionName} --data '${data}'`,
)
.toString();
const executionId = executeResultOutput.split(': ')[1];
const logs = cp
.execSync(
`gcloud beta functions logs read ${cloudFunctionName} --execution-id ${executionId}`,
)
.toString();
console.log(logs);
expect(logs).toContain('campaign: {"id":"1"}');
});
});
});
I want to print the logs to stdout, but logs is empty string.
But when I read logs using gcloud command line, it's ok. The stdout is correct:
gcloud beta functions logs read deleteCampaign --execution-id ee5owvtzlekc
LEVEL NAME EXECUTION_ID TIME_UTC LOG
D deleteCampaign ee5owvtzlekc 2018-09-13 12:46:17.734 Function execution started
I deleteCampaign ee5owvtzlekc 2018-09-13 12:46:17.738 campaign: {"id":"1"}
D deleteCampaign ee5owvtzlekc 2018-09-13 12:46:17.742 Function execution took 9 ms, finished with status: 'ok'
I use jest and nodejs write some tests for my cloud functions. Why the logs is empty string?
The string you are trying to get is empty, because the logs take a bit more time to generate. Even though the Google Cloud Function has finished executing, you'll have to wait a few seconds for the logs to be ready.
Reading your code, you are not letting this happen, hence you are getting an empty string.
The first thing that I noticed reading your code was this part:
const executionId = executeResultOutput.split(': ')[1];
I understand that you want to extract the Google Cloud Function's Execution ID. I had problems here because the string was not limited to the execution ID, it also included a new line character and the word "result". I made sure to just extract the necessary Execution ID with the next code:
const executionId = executeResultOutput.split(':')[1]; //We get the GCP ID.
const executionId2 = executionId.split("\n")[0].toString(); //removing the right part of the string.
If you have found the way to get the execution ID without problems then ignore my code.
Below you can find the code that has worked for me implementing functions.
let cloudFunctionLog ='';
function getLogs(){
console.log('Trying to get logs...');
const logs = cp
.execSync(`gcloud beta functions logs read ${cloudFunctionName} --execution-id ${executionId2}`);
return logs;
}
do{
cloudFunctionLog=getLogs();
if(!cloudFunctionLog){
console.log('Logs are not ready yet...');
}else{
console.log(`${cloudFunctionLog}`);
}
}while(!cloudFunctionLog);//Do it while the string comes empty.
When the logs are no longer empty, they'll show up in your console.
If I execute a certain shell command in node js, the output is on the console. Is there a way I can save it in a variable so it can be POST to Sqlite database.
const shell = require('shelljs');
shell.exec('arp -a');
In this scenario, I want to store the IP address of a specific MAC/Physical address into the database. How can this be done?
Any help would be much appreciated. Thank you
You need to get the output of the command you're passing to exec. To do that, just call stdout, like this:
const shell = require('shelljs');
const stdout = shell.exec('arp -a').stdout;
Then just parse that output to get your ipaddress:
const entries = stdout.split('\r\n');
// entries sample
[ '',
'Interface: 10.17.60.53 --- 0xd',
' Internet Address Physical Address Type',
' 10.11.10.52 6c-4b-90-1d-97-b8 dynamic ',
' 10.10.11.254 xx-yy-53-2e-98-44 dynamic ']
Then you can filter your wanted address with some more manipulation.
EDIT:
To get the ip address, you could do:
let ipAddr = null;
for (let i = 0; i < entries.length; i++) {
if (entries[i].indexOf('6c-4b-90-1d-97-b8') > -1) {
ipAddr = entries[i].match(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/)[0];
break;
}
}
console.log(ipAddr); // '10.11.10.52'
I'm merely copy pasting from the docs. You should research more.
You need to add a listener to stdout
var child = exec('arp -a', {async:true});
child.stdout.on('data', function(data) {
/* ... do something with data ... */
});
Or adding the callback directly when calling exec
exec('some_long_running_process', function(code, stdout, stderr) {
console.log('Exit code:', code);
console.log('Program output:', stdout);
console.log('Program stderr:', stderr);
});
You can access the result of the command run using shell.exec with the .output property. Try the code below.
var shell = require('shelljs');
var result = shell.exec('arp -a').output;
If you don't want the result in the console, you can specify the silent option.
var result = shell.exec('arp -a', {silent: true}).output;
Now, you can use regular expressions to extract ip and mac address from the result.
I am getting the result of the command like below:
? (xxx.xxx.xxx.xxx) at xx:xx:xx:xx:xx:xx [ether] on eth0
? (yyy.yyy.yyy.yyy) at yy:yy:yy:yy:yy:yy [ether] on eth0
You can use the following code to extract ip and mac.
var res = result.split("\n").map(function(item){
return item.match(/\((\d+\.\d+\.\d+\.\d+)\) at (..:..:..:..:..:..)/);
});
console.log(res[0][1]); //IP of first interface
console.log(res[0][2]); //MAC of first interface
console.log(res[1][1]); //IP of second interface
console.log(res[1][2]); //MAC of second interface
NOTE
I was not able to find the .output property in the documentation but trying the shell.exec function in the node console revealed it.
The .stdout property or the exec function mentioned in other answers doesn't work for me. They are giving undefined errors.
I'm trying to use mock-cli to stub process.arv in mocha tests for a cli app. I want to test that a message is console.logged when an incorrect argument ("imit") is passed to process.argv (as defined by commands).
I'm trying to adapt the example from the documentation but i don't think i have set everything up correctly.
it passes when i comment out "stdin: require('../mocks/fakeInputStream'), // Hook up a fake input stream" though i know it's not working correctly
it fails with TypeError: sourceStream.on is not a function when run as described below
Can someone see what I'm missing?
/index.js
var commands = ['init'];
function getGitHeadArgs() {
return process.argv.slice(2, process.argv.length);
}
if (getGitHeadArgs().length) {
if (!commands.includes(getGitHeadArgs()[0])) {
console.log("Silly Githead! That's not a githead command");
}
eval(getGitHeadArgs()[0])();
} else {
console.log("You didn't tell githead to do anything!");
}
/testIndex.js
var assert = require('assert');
var index = require('../index.js');
var mockCli = require("mock-cli");
describe("incorrect argument", function() {
it("imit throws an error if an invalid command is raised", function() {
var argv = ['node', '../index.js', 'imit']; // Fake argv
var stdio = {
stdin: require('../mocks/fakeInputStream'), // Hook up a fake input stream
stdout: process.stdout, // Display the captured output in the main console
stderr: process.stderr // Display the captured error output in the main console
};
var kill = mockCli(argv, stdio, function onProcessComplete(error, result) {
var exitCode = result.code; // Process exit code
var stdout = result.stdout; // UTF-8 string contents of process.stdout
var stderr = result.stderr; // UTF-8 string contents of process.stderr
assert.equal(exitCode, 0);
assert.equal(stdout, "Silly Githead! That's not a githead command\n");
assert.equal(stderr, '');
});
// Execute the CLI task
require('../index.js');
// Kill the task if still running after one second
setTimeout(kill, 1000);
});
Is ../mocks/fakeInputStream a valid path?
Is the object at ../mocks/fakeInputStream a valid instance of ReadableStream?
The source code is avalible at GitHub.
Make sure you meet the requirements for the captureStdin(sourceStream, callback) function.
The module uses that function to capture your fakeInputStream and pipe it into a captureStream.