Passing a node.js script an argument with a space on Windows - node.js

I'm running a node script from the command line on Windows and am trying to pass in a folder path that includes a space. When accessing this argument, via require modules or via the process.argv variable I don't seem to get what I would expect. For the following command:
node script.js "C:\path\to\folder\with a space\"
I seem to get the following value:
process.argv[2] = C:\path\to\folder\with a space\"
Notice the trailing " in the string. If the argument is passed without quotes, it obviously passes it as different arguments split on the space.
Am I doing something wrong, or is this a bug? And if it is a bug, is there a possible workaround?

The trailing backslash escapes the quote which is then again implied by the shell (instead of aborting due to lack of a closing quote).
The fix is simply escaping that backslash with another backslash or omitting it altogether:
C:\Users\myself> python -c "import sys; print sys.argv[1]" "foo\bar\"
foo\bar"
C:\Users\myself> python -c "import sys; print sys.argv[1]" "foo\bar\\"
foo\bar\
Note that you may only escape the last backslash this way - any other backslash ins the string will not act as an escape character:
C:\Users\myself> python -c "import sys; print sys.argv[1]" "foo\\bar\\"
foo\\bar\

Related

Argument escaping not interpreted correctly when running node.js script from Windows PowerShell

Given the following script:
const yargs = require('yargs');
const argv =
yargs
.usage('Usage: $0 [--whatIf]')
.alias('d', 'directory')
.alias('wi', 'whatIf')
.nargs('d', 1)
.describe('d', 'alphabetize this directory')
.describe('whatIf', 'show what would happen if run')
.demandOption(['d'])
.argv;
console.log(argv.directory);
If I invoke the script from Windows PowerShell like so: node .\alphabetizer.js -d 'l:\my folder\Files - Some Files In Here\' --whatIf I get the output l:\my folder\Files - Some Files In Here\" --whatIf where I would expect just l:\my folder\Files - Some Files In Here\. It works OK with folder names that require no escaping, but it seems to get confused by the escaping.
If I examine process.argv, I can see the same escaping issue.
I have noticed that if I remove the trailing slash it will work. However, this still points to the node script not handling the input properly, because this should not be necessary with string set off by single quotes.
Is there a way to make this work?
Both Windows PowerShell (powershell.exe) and PowerShell [Core] v6+ (pwsh) are fundamentally broken with respect to quoting arguments for external programs properly - see this answer for background info.
Generally, PowerShell on Windows has to perform re-quoting behind the scenes in order to ensure that just "..."-quoting is used, given that external programs can't be assumed to understand '...'-quoting too when parsing their command line (which on Windows every program has to do itself).
Windows PowerShell is more broken with respect to arguments that end in \ and have embedded spaces, re-quoting them improperly; e.g.:
PS> foo.exe 'c:\foo \' bar
is translated into the following command line behind the scenes:
foo.exe "c:\ foo \" bar
This is broken, in that most applications - including PowerShell's own CLI - sensibly assume that the \" is an escaped " char. to be taken verbatim, thinking that the argument continues with  bar and then implicitly ends, despite the formal lack of a closing ".
PowerShell [Core] v6+ more sensibly translates the above to foo.exe "c:\foo \\" bar, where the \\ is interpreted as an escaped \, and the following " again has syntactic function.
If you're stuck with Windows PowerShell, your only choices are:
either: if possible, leave off the trailing \
otherwise: manually double it (\\), but only do so if the argument also contains spaces (otherwise, the \\ will be retained as-is, though in the case of filesystem paths that is usually benign).

converting a string passed from unix shell to a node program to a javascript-formatted one?

I'm using a bash script to send an argument to a node app like so:
testString="\nhello\nthere"
node ./myNodeScript.js $testString
The trouble comes when I use testString inside the node program after capturing it as process.argv[2] -- rather than expand the \n characters to newlines node prints them literally. I need a way to tell node to convert the argument to a javascript string, respecting the formatting characters. Is there a way to go about this?
Try to avoid confusing literal linefeeds and literal backslash followed by literal n.
If you want the string you pass to have linefeeds, you should ignore JavaScript string literal syntax and just pass the linefeeds as linefeeds:
$ cat myNodeScript.js
console.log("Node was passed this: " + process.argv[2])
$ cat myBashScript
testString='
hello
there'
printf 'Bash passes this: %s\n' "$testString"
node myNodeScript.js "$testString"
$ bash myBashScript
Bash passes this:
hello
there
Node was passed this:
hello
there
Arguments should contain data (linefeed) while script files should contain code (quoted linefeed or expanded \n as appropriate in the language). When you make sure not to confuse code and data, you can trivially handle both backslash-en and linefeeds in the same string with no surprises:
testString='
"\nhello\nthere" is JavaScript syntax for:
hello
there'
There are ways to express this on a single line in bash using \n for linefeeds and \\n for backslash-en, you just need to make sure that it remains as code, and doesn't accidentally make it into the variable as data.
Can you try this:
testString=$( printf "\nhello\nthere")
node ./myNodeScript.js "$testString"
And let me know if it works?

Backslashes are removed unless quoted in command line flags

I'm using the flag package to interpret flags entered at the command line.
I created a variable using
ptrString := flag.String("string", "", "A test string")
flat.Parse()
Then when I want to print it,
fmt.Println("You entered " + *ptrString)
If I enter something like -string=hello! as a command line argument, it prints "hello!"
If I enter something like -string=hello\Bob as a command line argument, it prints "helloBob"
Is there a recommended way to convert or interpret the flag argument to a string that doesn't remove the backslash? (This is being tested on Linux and OS X, if the shell is interfering...)
Characters that have special meaning in the shell need to be quoted or escaped. You can find complete list in the shell's man pages (under "Quoting" in man 1 bash).
In this case, you can either quote or escape the baskslash
-string=hello\\Bob
// or
-string='hello\Bob'

Multiword string as a curl option using Bash

I want to get some data from a HTTP server. What it sends me depends on what I put in a POST request.
What I put in the INPUT_TEXT field is a sequence of words. When I run the following command, I get good looking output.
$ curl http://localhost:59125/process -d INPUT_TEXT="here are some words"
I want a bash script to take some string as a command line argument, and pass it appropriately to curl. The first thing I tried was to put the following in a script:
sentence=$1
command="curl http://localhost:59125/process -d INPUT_TEXT=\"${sentence}\""
$command
I then run the script like so:
$ ./script "here are some words"
But then I get a curl Couldn't resolve host error for each of "are", "some", and "words". It would seem that "here" got correctly treated as the INPUT_TEXT, but the rest of the words were then considered to be hosts, and not part of the option.
So I tried:
command=("curl" "http://localhost:59125/process" "-d" "INPUT_TEXT='$sentence'")
${command[#]}
I got the same output as the first script. I finally got what I wanted with:
result=$(curl http://localhost:59125/process -d INPUT_TEXT="${sentence}")
echo $result
I'm still unsure as to what the distinction is. In the first two cases, when I echoed out the contents of command, I get exactly what I input from the interactive Bash prompt, which had worked fine. What caused the difference?
The following will work:
command=("curl" "http://localhost:59125/process"
"-d" "INPUT_TEXT=$sentence")
"${command[#]}"
That has two changes from yours:
I removed the incorrect quotes around $sentence since you don't want to send quotes to the server (as far as I can see).
I put double-quotes around the use of "${command[#]}". Without the double quotes, the array's elements are concatenated with spaces between them and then the result is word-split. With double quotes, the individual array elements are used as individual words.
The second point is well-explained in the bash FAQ and a bunch of SO answers dealing with quotes.
The important thing to understand is that quotes only quote when a command is parsed. A quote which is a character in a variable is just a character; it is not reinterpreted when the value of the variable expanded. Whitespace in the variable is used for word-splitting if the variable expansion is unquoted; the fact that the whitespace was quoted in the the command which defined the variable is completely irrelevant. In this sense, bash is just the same as any other programming language.

Semicolon on command line in linux

i am running my application in linux by providing inputs as command line. My input field contain an argument which contains ";"(semicolon) internally.(For example:123;434;5464).
This will be parsed using UTF8String encode and send.
But when i am using like this, in initial itself i am getting,
bash: 434: command not found
bash: 5464: command not found
And when i capture traffic the output contains only 123 instead 123;434;5464
But if i give without semicolon (Ex:123:434:5464),not getting any problem output coming properly as 123:434:5464
Point me how to give command line input by using semicolon as to come output. Is there any particular syntax to use while doing with semicolon.
I am running like below
./runASR.sh -ip 10.78.242.4 -port 3868 -sce 10.78.241.206 -id 85;167838865;1385433280
where -id field contain that value with issue.
; is treated an end of command character. So 123;456;5464 to bash is in fact 3 commands. To pass such meta-characters escape it with escape character \.
./command 123\;456\;5464
Or Just quote it with single quote (double quote evaluates the inner string) (Thanks Triplee, I forgot to mention this)
./command '123;456;5464'

Resources