Why does npm start ignore escaped backticks from argument? - node.js

I have a super simple index.js file that outputs the first argument it receives:
// Args 0 & 1 are /usr/bin/node and path to file
console.log(process.argv[2]);
When I run the following:
node index.js test``backticks
the output is testbackticks, and as expected, the backticks are ignored.
Calling this again, with escaping this time:
node index.js test\`\`backticks
the output is test``backticks.
My package.json has a start script like so:
"start": "node ./index.js"
Calling npm start -- test``backticks will result in them being ignored, just like with the node.js call.
However, calling this with escaping:
npm start -- test\`\`backticks
Also results in the same output, which is simply:
testbackticks
With the backticks ignored as well.
Escaping npm start with double or single quotes worked fine, it is just the backticks that are ignored.
Why does calling npm start and node produces different results and how come backticks can't be escaped in npm start ?
Lastly, how can I, if possible, pass a string with backticks as an argument to npm start ?

Related

-print printing out string via npm but actually evaluating through powershell

The following script is defined in my package.json:
"abc": "node -p 'p=require(\"./package\");p.main=\"lib\";p.scripts=p.devDependencies=undefined;JSON.stringify(p,null,2)'",
If I run 'npm run-script abc' I end up with a package.json with the string
'p=require(\"./package\");p.main=\"lib\";p.scripts=p.devDependencies=undefined;JSON.stringify(p,null,2)'
If I run the command:
node -p 'p=require(\"./package\");p.main=\"lib\";p.scripts=p.devDependencies=undefined;JSON.stringify(p,null,2)'
Directly in powershell I actually get the json output I'm looking for.
Not sure why the difference? I tried using -e/-eval as well to no avail, it seems to think that it just prints out the script?
Change your npm script to the following instead:
"abc": "node -p \"p=require('./package');p.main='lib';p.scripts=p.devDependencies=undefined;JSON.stringify(p,null,2)\"",
Your npm script will now run succesfully via Powershell, Command Prompt (cmd.exe), Linux, and MacOS.
Changes are as follows:
The node/js code has been wrapped in JSON escaped double quotes \"...\" instead of single quotes.
The actual node/js code itself utilizes single quotes '...' instead of JSON escaped double quotes \"...\" because using escaped double quotes in JavaScript is invalid syntax.
"abc": "node -p \"p=require('./package');p.main='lib';p.scripts=p.devDependencies=undefined;JSON.stringify(p,null,2)\"",
^^ ^ ^ ^ ^ ^^
It's a quoting issue.
The problem is that running npm run-script abc is not interpreted in powershell (which properly supports both single and double quotes), but in cmd.
You can either:
Replace single quotes with double quotes, and use proper escaping (although the result may be a bit ugly):
"abc": "node -p \"p=require(\\\"./package\\\");p.main=\\\"lib\\\";p.scripts=p.devDependencies=undefined;JSON.stringify(p,null,2)\""
Use single quotes inside the javascript code and double qoutes to surround the script
"abc": "node -p \"p=require('./package');p.main='lib';p.scripts=p.devDependencies=undefined;JSON.stringify(p,null,2)\""

how to escape whitespace in Node-RED exec node command

Situation:
In my Node-RED flow there is a call to another program where I use the exec node.
The arguments are set-up in a function node and passed as the msg.payload to the exec node.
This works fine and returns the expected results as long as the command has no space in it.
Problem:
A customer cannot use the call to the command on his system, because the path tp the installation of the program contains a whitespace.
What I tried and didn't work:
Escaping the whitespace with ^ as read in another question: /opt/path^ toProgram^ directory/program
Escaping the whitespace with \\: /opt/path\\ toProgram\\ directory/program
Quoting the whole string with "": "/opt/path toProgram directory/program"
Quoting the whole string and escaping the whitespace: "/opt/path\\ toProgram\\ directory/program"
Quoting the whole string with '': '/opt/path toProgram directory/program'
Leaving the command line empty/""and combining any of the above points with its arguments to one string (in the function node that sets up the arguments for that exec node) and passing it on as the msg.payload -> input parameters in the exec node config panel. No Success.
What's not the problem:
The program itself works fine, on mine and on the customers system, it's only the path that is different
Other than that specific command string with whitespace, the configuration of the exec node and its msg.payload ( = input parameters or arguments) as well as the "use spawn() instead of exec()?" is fine and works
Request
Is there any other way to escape the whitespace that I'm not aware of so the path to the program can be found? From my understanding the whitespace is interpreted as a separator for the input arguments, which it should be, but not on the command string.
This should be a quick fix in my opinion, however nothing seems to work that usually works in node, js, php or bash.. thanks in advance for any hints and ideas!
Environment:
Node-RED version: v0.15.2 |
Node.js version: v5.12.0 |
Mac OS X 10.11.6 = Darwin 15.6.0 x64 LE
Screenshots
This is the part of the flow:
This config works:
This config does not work:
I've just tested this and option 3 (Quoting the path with "") works fine.
Putting "/home/foo/foo bar/date" in the command section of the exec node executed the binary correctly
After a good nights sleep the solution (at least what I thought at the time) was to adapt the exec node in node-red itself: The original code appended the additional arguments (the ones separated by whitespace) to the command, and then slice the whole string by whitespace into an array (node.cmd is the path to the command with or without whitespace):
before: var arg = node.cmd; arg += " "+msg.payload; arg = arg.match(/(?:[^\s"]+|"[^"]*")+/g);
and the (earlier, incomplete) solution was to prepend the command with the builtin array.unshift(<value>) function to the array after the slice operation, so that the command path with the whitespace is not affected by the array creation:
after: var arg = ""; ...add msg.payload and slice arg string into array.. arg.unshift(node.cmd);
The file can be found at: nodered node 75-exec.js on github, in the lines 46-51
Update to real solution:
After further investigation it was clear, that the Use spawn() instead of exec()? option was the problem: the command part with whitespace in double quotes and using exec() worked fine. And my approach couldn't be used when the command path contained an argument, e.g. in /home/foo bar/date -r 1000.
Following the issue at the official github repository of node-red the command part to the arguments array at the beginning after the slice but instead to have the command path with whitespace in quotes and later unwrapping them, copying the behaviour when exec() is used. He added this line in the original file after line 51: if (/^".*"$/.test(cmd)) { cmd = cmd.slice(1,-1); } and now both spawn() and exec() work the same - credits to him, unfortunately I don't know his username here.

Colored logging in terminal with NPM run script

I'm trying to setup a project exclusively with NPM as a build system (no Gulp or Grunt) so I'm a bit of a beginner, but so far it's working pretty nicely except for this little road block.
The scripts section of my package.json looks something like that :
"scripts": {
"clean:task": "rimraf dist/*",
"clean:notify": "notify --t 'Cleaning done.' --m 'dist/ has been cleaned successfully.",
"clean": "npm run clean:task -s && npm run clean:notify -s",
"serve": "browser-sync start --p 'xxx.dev/app' --host 'xxx.dev' --port '3000' --open 'external' --f 'app'",
"styles:task": "node-sass --output-style nested -o app/assets/css app/assets/css",
"styles:notify": "notify --t 'Styles compilation' --m 'Styles have been compiled successfully'",
"styles:build": "npm run styles:task && npm run autoprefixer",
"imagemin": "imagemin app/assets/img dist/img -p",
"scripts:lint": "jshint --reporter=node_modules/jshint-stylish app/assets/js/scripts.js"
}
I have notifications to announce successful tasks, but ideally I'd like some nice colored messages directly in the terminal. I know this can be done with Gulp via colored logging but I can't fin any NPM package that has a CLI that would be able to do that.
Any ideas ? Is it even possible ?
Thanks for your help.
Individual scripts defined in package.json can output a message to Mac's Terminal in color by following a syntax that boils down to echo + ANSI color reference + some text although you can get more complicated than this, as well.
Step 1: Define your scripts
"scripts": {
"greeting": "echo \"\\033[32mHello World\"",
"notification": "echo \"\\033[33mThe Server Has Started\"",
"timestamp": "echo \"\\033[31m--------\";date \"+%H:%M:%S\n--------\n\" && echo \"\\033[00m\""
{
Step 2: Run your scripts
npm run greeting
npm run notification
npm run timestamp
Some things to note
Escaping is inherently a part of this. A comment by James Lim on StackOverflow mentions the use of -e which apparently ensures that echo honors escaping slashes. I found this was necessary when running the command directly in Terminal but unnecessary when firing it as part of npm run <script>.
The ANSI code that sets the color is made up of eight characters that always begin with a backslash, like this \033[32m. Also, notice that the text I am outputting in my scripts above begins immediately after the last character in the ANSI code– this is so the message will be flush left in the Terminal.
In the timestamp script above, the semicolon separates the echo and date commands but maintains the same color we set at the beginning. In fact, this color will affect everything defined in this script and, in my case, even changed the color of a message output by a separate script that immediately followed this one. For this reason, I included another echo that simply resets the color to the Terminal's default color (in this case, black).
For reference, I could have used && in place of the semicolon and achieved the same results. If you do not already know the difference between these two operators, see this post.

Passing arguments in Express JS

I am trying to specify 2 arguments with express JS start command, as specified below:
npm start -x 5 -y 43
But in doing so, I can't pick the arguments with '-' and they are somehow skipped in the following code.
process.argv.forEach(function (val, index, array) {
log.info(index + ': ' + val);
log.error("========="+array[index].toString());
});
Please help me to get the arguments with '-' as initials?
Note: I have tried using Yarks, but its not working as specified in the manual.
To pass arguments in npm script you must use double dash --:
npm start -- -x 5 -y 43
Check npm-run-script command documentation for more details.
I was able to pass in arguments with simply
npm start myArg1 myArg2
Both bin/www and app.js could access them.

How to preserve quotes in a bash parameter?

I have a bash script (Mac OS X) that in turns calls a Node.js command line application.
I normally call the Node.js app like this:
node mynodeapp events:"Open project"
Which node has no problem parsing as one parameter, in spite of the space between "Open" and "project".
I call my bash script like this:
. mybashscript.sh 2014-03-20 "Open project"
Inside the bash script I have:
EVENTSQUOTES=\"$2\"
echo node mixpanel-extract date:$1 events:$EVENTSQUOTES
node mixpanel-extract date:$1 events:$EVENTSQUOTES
Running the script produces:
node mixpanel-extract date:2014-03-20 events:"Open project"
Parameters: { date: '2014-03-20',
events: [ '"Open' ] }
So although the echo output line looks fine, the Parameters: output from my Node.js app tells me that bash splits the parameter in two. I've also tried wrapping it in more quotes e.g. EVENTSQUOTES='\"$2\"' but it makes no difference.
You need to use quote while calling also:
node mixpanel-extract date:"$1" events:"$EVENTSQUOTES"
echo node mixpanel-extract "date:$1" "events:$2"
node mixpanel-extract "date:$1" "events:$2"
You need to quote the variable when you use it as well, otherwise word splitting will occur.

Resources