Node.js Shell Script And Arguments - bash

I need to execute a bash script in node.js. Basically, the script will create user account on the system. I came across this example which gives me an idea how to go about it. However, the script itself needs arguments like the username, the password and the real name of the user. I still can't figure out how to pass those arguments to the script doing something like this:
var commands = data.toString().split('\n').join(' && ');
Does anyone have an idea how I can pass those arguments and execute the bash script within node.js over an ssh connection.
thanks

See the documentation here. It is very specific on how to pass command line arguments. Note that you can use exec or spawn. spawn has a specific argument for command line arguments, while with exec you would just pass the arguments as part of the command string to execute.
Directly from the documentation, with explanation comments inline
var util = require('util'),
spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/usr']); // the second arg is the command
// options
ls.stdout.on('data', function (data) { // register one or more handlers
console.log('stdout: ' + data);
});
ls.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
ls.on('exit', function (code) {
console.log('child process exited with code ' + code);
});
Whereas with exec
var util = require('util'),
exec = require('child_process').exec,
child;
child = exec('cat *.js bad_file | wc -l', // command line argument directly in string
function (error, stdout, stderr) { // one easy function to capture data/errors
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
Finally, note that exec buffers the output. If you want to stream output back to a client, you should use spawn.

var exec = require('child_process').exec;
var child = exec('cat *.js | wc -l', function(error, stdout, stderr) {
if (error) console.log(error);
process.stdout.write(stdout);
process.stderr.write(stderr);
});
This way is nicer because console.log will print blank lines.

You can use process.argv. It's an array containing the command line arguments. The first element will be node the second element will be the name of the JavaScript file. All next elements will be any additional command line you given.
You can use it like:
var username = process.argv[2];
var password = process.argv[3];
var realname = process.argv[4];
Or iterate over the array. Look at the example: http://nodejs.org/docs/latest/api/all.html#process.argv

Related

Running bash script from Deno

Let’s say I’ve got this super useful and advanced bash script:
#!/usr/bin/env bash
echo What is your name?
read name
echo What is your age?
read age
When I try to run it from Deno with a simple script like this:
const process = Deno.run({
cmd: [`./bash.sh`],
stdin: "piped",
stdout: "piped",
});
const decoder = new TextDecoder();
const output = await process.output()
const parsed = decoder.decode(output);
console.log(parsed);
It returns nothing, but if I simplify the Deno script to the first line of the bash script it returns the output just fine
const process = Deno.run({
cmd: [`echo`, `What is your name?`],
stdin: "piped",
stdout: "piped",
});
const decoder = new TextDecoder();
const output = await process.output()
const parsed = decoder.decode(output);
console.log(parsed);
Why is this? I’d assume since the start of the bash file and the single line command both start with echo it would return the same result twice
Version 1.5 of deno added the prompt function which allows you to completely remove the need for shelling out to a different program and handling inter-process communication via stdin/stdout.
let name: string | null = null;
let age: string | null = null;
while (name === null) {
name = prompt("What is your name?");
}
while (age === null) {
age = prompt("What is your age?");
}
console.log(`you are ${name}, ${age}yo`);
Your code is telling Deno to set up the subprocess to expect piped stdin -- but never providing it any content on stdin! Consequently, it hangs in the very first read.
If we take that out (letting stdin be passed through from the parent process), and do in fact answer the two prompts on the parent process's stdin, everything works perfectly:
deno run --allow-run run-bash.js <<'EOF'
A Nony Mouse
3
EOF
...with run-bash.js containing:
const process = Deno.run({
cmd: [`./bash.sh`],
stdout: "piped",
});
const decoder = new TextDecoder();
const output = await process.output()
const parsed = decoder.decode(output);
console.log(parsed);
...and your bash.sh unchanged. output thus captures the two prompts (What is your name? and What is your age?), and forwards them to the javascript interpreter's stdout as-requested.
You have to call bash to call your script
( of course with --allow-run option )
like :
const process = Deno.run({
cmd: ["bash","bash.sh"],
stdin: "piped",
stdout: "piped",
});
const decoder = new TextDecoder();
const output = await process.output()
const parsed = decoder.decode(output);
console.log(parsed);

Working with returned value in [for] loop

I have an experience with C#, where I can work with commands from user like this:
string command;
while ( (command = GetCommandFromUser()) != EXIT_COMMAND )
ProcessCommand(command);
This simple code allows me get command from user (from Console or something like this) and process it.
But in Go I have only this code:
var command string
for command = GetCommandFromUser(); command != ExitCommand; command = GetCommandFromUser() {
ProcessCommand(command)
}
Can I do it simply?
for {
command := GetCommandFromUser()
if command == ExitCommand {
break
}
ProcessCommand(command)
}

JScript: identifying whether double quotes are passed to a WSH script

There are situations when it is important to identify whether double quotes are passed as arguments to a WSH script. For example because they should be passed to another executable to be run.
The standard parsing functions/objects:
objArgs = WScript.Arguments;
for (i = 0; i < objArgs.length; i++)
{
WScript.Echo(objArgs(i));
}
do not differentiate between:
cscript foo.js "bar"
and
cscript foo.js bar
Is it possible with some other approach?
Note: I also tried to sort of escape them with several combinations like:
cscript foo.js '"bar"'
It seems that they are simply stripped away.
Following #Ekkehard.Horner suggestions:
Solution
// parseArgs.js
// Parsing jscript script arguments verbatim
var Shell = new ActiveXObject("WScript.Shell"),
wmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\cimv2"),
guid = (new ActiveXObject("Scriptlet.TypeLib")).GUID.substring(0,38),
windir=Shell.ExpandEnvironmentStrings("%WinDir%"),
winver="\"" + windir + "\\System32\\winver.exe\" " + guid,
pcol, pid, cmd;
// Run winver.exe hidden and get this script ID as its ParentProcessId
winver=winver.replace(/\\/g, "\\\\");
Shell.Run("winver " + guid, 0);
pcol = new Enumerator (wmi.ExecQuery(
"SELECT * From Win32_Process WHERE CommandLine='"+ winver + "'",
"WQL", 32));
for (; !pcol.atEnd(); pcol.moveNext()){
var prc = pcol.item();
pid=prc.ParentProcessId;
prc.Terminate;
}
// Get the command line for the found PID
pcol = new Enumerator (wmi.ExecQuery(
"SELECT * From Win32_Process WHERE ProcessID="+ pid,
"WQL", 32));
for (; !pcol.atEnd(); pcol.moveNext()){
var prc = pcol.item();
cmd =prc.CommandLine;
}
WScript.Echo(cmd);
// Parse command line for arguments
var ags,
parseCmd=function(cmd){// WMI trims initial spaces
var p = new Object(),
re =/^"/.test(cmd) ? /"[^"]+" */ : /\S+\s*/;
p.nxt=re.test(cmd) ? cmd.match(re)[0] : ""; // extract next token
p.rst=cmd.replace(re, "") ; // remainder
return(p);
}
// Strip c/wscript path
ags=parseCmd(cmd).rst
//WScript.Echo(ags);
// Remove WSH "//xxx" options
ags=ags.replace(/\/\/\w+ +/g, "")
//WScript.Echo(ags);
// Strip script name and get arguments
ags=parseCmd(ags).rst
WScript.Echo(ags);
// Loop args and store as an array
var i=1, aags=[];
while(ags != ""){
var p =parseCmd(ags);
ags=p.rst;
aags.push(p.nxt.replace(/ +$/, ""));
WScript.Echo(i, p.nxt);
i++;
}
WScript.Echo(aags);
Test
Running parseArgs.js gives:
> cscript //nologo parseArgs.js "hello" world
cscript //nologo parseArgs.js "hello" world
"hello" world
1 "hello"
2 world
"hello",world
The line:
> parseArgs.js "hello" world
gives similar results.
Comments
Do we need such a convoluted script? Short answer: no. Long: depends.
In general, assuming you know the name of your script when it is run, you could query WMI for it.
Anyway, when you deploy your script, you do not normally have control on the deploy directory. So, if there is another script running under the same name, you can't know for sure which one is yours.
Another not so edge case is when there are two or more instances of your script running.
The strategy here is to run some dummy standard Windows executable (winver.exe) hidden, passing to it a GUID. In this way, it is safe to identify winver.exe command line by the unique GUID and consequently your script as the parent of winver.exe.
winver.exe does not require arguments, but does not protest if you pass some to it.

How to excute .bat script on windows from node js

I have node js file which will excute my bat file. I tried using exec of node js child-process module but no luck
Let me share you my node js script:
var startTime = '2014-11-27 17:0:42';
var threadName = '<Thread 0>';
var categoryName ='AlarmCategory';
var alarmLevel = 'Fatal';
var alarmCategory = 'OS';
var alarmMessage = 'corrupt';
var cp = require('child_process');
msg = cp.exec('handler.bat' +" " + startTime ,function (error, stdout, stderr) {
if (error) {
console.log(error.stack);
console.log('Error code: '+error.code);
console.log('Signal received: '+error.signal);
}
console.log('Child Process STDOUT: '+stdout);
console.log('Child Process STDERR: '+stderr);
});
My bat script . This script takes input parms and echos.
#echo off
set startTime=%1
set thread=%2
set categoryName=%3
set alarmLevel=%4
set alarmCategory=%5
set alarmMessage=%6
Echo #####################
Echo This tool will help you get the users info
Echo #####################
Echo hi %arg1%
For now i am printing only one arg.
Error i am getting :
"C:\Program Files (x86)\JetBrains\WebStorm 8.0.4\bin\runnerw.exe" "C:\Program Files\nodejs\node.exe" test\test_cmd.js
Error: Command failed: 'handler.bat' is not recognized as an internal or external command,
operable program or batch file.
I resolved my issue. I am using execFile() function now since i also need to pass arguments. It is very important to note that when you use execute command using execFile() make sure you set the "cwd" option in command of exeFile(). Since it looks for the child process file and it does not find the file. Setting full path directly for .bat file do not work .
I did like this ,
msg = cp.execFile('handler.bat' ,[startTime,threadName] ,{cwd:'/Node Js/baflog/sigma-logger/test'},function (error, stdout, stderr) {
.... ..
...
}

D: executeShell on Windows to run another program not returning immediately

I'm using D as a scripting language for Windows 7 console stuff to automate boring tasks. One of my scripts (open.exe) is supposed to allow me to open stuff from the command line without me having to specify which program I use (I have a configuration file with this stuff). Now, I use executeShell to do this, and call something like start [name of program I want to use] [name of input file]. If I do this directly from the shell, it returns immediately, but if I do it using my D script, it doesn't return until the program that it opens is closed. What should I do to allow it to return immediately?
For reference purposes, this is the business logic of my script (the main method just does some argument parsing for piping purposes):
immutable path = "some//path//going//to//config//file.conf";
void process(string input) {
string extension = split(input,".")[1]; //get file extension from input
auto config = File(path,"r"); auto found = false;
while (!config.eof()){
auto line = chomp(config.readln());
if (line[0]!='#') { //skip comment lines
auto divided = split(line, ":");
if (divided[0] == extension) {
found = true;
auto command = "start " ~ divided[1] ~ " " ~ input;
auto result = executeShell(command);
//test for error code and output if necessary
writeln(result.output);
}
}
}
if (!found)
writeln("ERROR: Don't know how to open " ~ input);
}
From the top of the std.process documentation:
Execute and wait for completion, collect output - executeShell
The Windows start program spawns a process and exits immediately. D's executeShell does something else. If you'd like to spawn another program, use the appropriate functions: spawnProcess or spawnShell.

Resources