This is how I am using function spawn from node:child_process package:
const args = [
'Djava.library.path=./DynamoDBLocal_lib',
'jar ./DynamoDBLocal.jar',
'inMemory'
]
const dynamodb = spawn('java', args, {cwd: './dynamodb_local'})
It looks like the path from the first argument, gets somehow changed along the way because stderr from this command logs this
Error: Could not find or load main class Djava.library.path=..DynamoDBLocal_lib
Caused by: java.lang.ClassNotFoundException: Djava/library/path=//DynamoDBLocal_lib
It looks like the slash gets converted to a dot and vice-versa?
This command, when used normally in a shell, works as expected.
Edit: I am running this on macOS.
You said it works fine in a shell, so I suggest you use the shell option (documentation). Just make sure not to pass unsanitized user input into it. You can do it like this:
const args = [
'-Djava.library.path=./DynamoDBLocal_lib',
'-jar ./DynamoDBLocal.jar',
'-inMemory'
]
const dynamodb = spawn('java', args, {cwd: './dynamodb_local', shell: true})
Note that with the shell option enabled, you'll need to add dashes to your arguments.
Related
I have an app creator and, using the Username NPM package, I can get the OS' username with this:
Browser.ExecJS("username.sync()")
Tested on Electron.
So, this is the format my app creator uses to read from JS:
Browser.ExecJS("")
In this example, it's calling username.sync(). And it works.
But when running this:
Browser.ExecJS("const{exec}=require(`child_process`);exec(`jq -r '.next_var' /tmp/eventsheet.json`,(error,stdout,stderr)=>{if(error){console.log(`error:${error.message}`);return}if(stderr){console.log(`stderr:${stderr}`);return}console.log(`${stdout}`);return});")
It gets "0". And then correctly logs the stdout on console.
But, it should get the same as it logs on console, instead of "0".
Its inspired by this code about how to run a native shell program directly from Electron/NodeJS: https://stackabuse.com/executing-shell-commands-with-node-js/
So, I think it should replace the console.log by some sort of return.
How do I re-factor it? Thanks in advance.
UPDATE: based on this suggested answer (that doesn't works), this is the closest template to put it to work using return instead of console.log as output:
const { promisify } = require('util');
const exec = promisify(require('child_process').exec)
module.exports.getGitUser = async function getGitUser () {
const name = await exec('git config --global user.name')
const email = await exec('git config --global user.email')
return { name, email }
};
But still doesn't works.
What I need is this:
const{exec}=require(`child_process`);exec(`jq -r '.next_var' /tmp/eventsheet.json`,(error,stdout,stderr)=>{if(error){console.log(`error:${error.message}`);return}if(stderr){console.log(`stderr:${stderr}`);return}console.log(`${stdout}`);return});
But using return instead of console.log.
In this case, I am using Node.js ChildProcess. Let's say the application file (index.js, for example) is in folder1. This folder also has folder2, which is where the class file is. So, when I call spawn from folder1, the command's current directory is folder1. However, I can't do java ./folder2/MyFile.
Here's what I tried:
async function run(path){
let child = spawn('java', [path], {
stdio: [process.stdin, process.stdout, process.stderr] //for testing purposes
})
}
Using function run on ./folder2/MyFile returns:
Error: could not find or load main class ..folder2.MyFile
I assume this has something to do with java and classpath. I saw an answer involving setting the classpath to the target directory (folder2) but it didn't do anything.
In short, how can I run a .class file from a different directory?
You can use exec instead of spawn so you can use two commands with & symbol which the second command runs when the first one finish without fail.
I think this might work for you.
const exec = require('child_process').exec;
exec("cd ./folder2 & java MyFile", function(
error: string,
stdout: string,
stderr: string
) {
console.log(stdout);
console.log(error);
console.log(stderr);
});
I'm working on a small cli tool that can automatically deploy Google Home actions based on the projects that are setup in a directory.
Basically my script checks the directories and then asks which project to deploy. The actual command that should run is coming from Google's cli gactions
To run it with arguments I setup a spawned process in my node-script:
const { spawn } = require('child_process')
const child = spawn('./gactions', [
'update',
'--action-package',
'<PATH-TO-PACKAGE>',
'--project',
'<PROJECT-NAME>'
])
child.stdout.on('data', data => {
console.log(data)
}
However, the first time a project is deployed, the gactions cli will prompt for an authorization code. Running the code above, I can actually see the prompt, but the script won't proceed when actually entering that code.
I guess there must be some way in the child process to capture that input? Or isn't this possible at all?
Simply pipe all standard input from the parent process to the child and all output from the child to the parent.
The code below is a full wrapper around any shell command, with input/output/error redirection:
const { spawn } = require('child_process');
var child = spawn(command, args);
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
process.stdin.pipe(child.stdin);
child.on('exit', () => process.exit())
Note that if you pipe stdout you don't need handle the data event anymore.
require( "child_process" ).spawnSync( "sh", [ "-c", "npm adduser" ], { stdio: "inherit", stdin: "inherit" } );
this will execute the command given as we normally do in terminal.
I have a Grunt task and if the --verbose command line flag is on, I want to echo some more info to the console.
Finding out if that flag is on isn't possible with grunt.option('verbose'). It also doesn't appear to be anywhere in grunt.package.
How can I see, from within a task, if the user has the verbose flag set?
That is imho because grunt.option works only for a grunt used flags, it doesnt take every shell argument you provide.
The esiest module-free solution is to parse your flag from process.argv, that returns an array.
Your flags would start at position 2, so if --verbose is the first argument, you would claim it by process.argv[2] How do I pass command line arguments?
You can easily test it by creating a javascript file
var args = process.argv;
process.argv.forEach( (val, index, array) => {
var flag = val.replace(new RegExp('-', 'g'), '');
console.log(flag);
});
and calling it in your shell
node testParams.js --argument1 -t.
The outcome will look like this
hakim#cortana:~/Sites/DOODLINGS $ node testParams.js --verbose -t
/usr/local/Cellar/node/7.5.0/bin/node
/Users/hakim/Sites/DOODLINGS/testParams.js
verbose
t
With some googling, you can find module to extract params for you. I dont use grunt so cant help you much there.
I have the following to execute shell commands using Node:
function puts( error, stdout, stderr ) {
stdout = sanitize( stdout ).rtrim("\n"); // remove new line
sys.puts( stdout );
}
I use this library to try and remove new lines:
npm install validator
but when I do something like this:
exec( "ls -l", puts );
it puts a new line character on the end.
I'm using Linux so the new line should just be a \n right?!
How do I stop the new line from happening?
Many thanks.
Are you sure that the call to sys.puts isn't what's adding the newline? Try sys.print and see what you get.
In other news, I think that sys.puts (and sys in general) have been deprecated in node.js for a while. You should probably use console.log for this kind of thing.