How do I avoid calling part of my string as a command? - bash

I run with the file with command line arguments:
samplebash.bsh fakeusername fakepassword&123
.bsh file:
echo "Beginning script..."
argUsername='$1'
argPassword='$2'
protractor indv.js --params.login.username=$argUsername --params.login.password=$argPassword
Output:
Beginning script...
123: command not found
The Issue: For some reason, it interprets what follows the & symbol from the password as a command, how do I avoid this?

The problem isn't happening in your script, it's happening in your original command line. & is a command terminator, which specifies that the command before it should be executed in the background. So your command was equivalent to:
samplebash.bsh fakeusername fakepassword &
123
You need to quote the argument to prevent special characters from being interpreted by the shell.
samplebash.bsh fakeusername 'fakepassword&123'
Also, you shouldn't put single quotes around a variable like you do in your assignments, that prevents the variable from being expanded. So it should be:
argUsername=$1
argPassword=$2
And you should put double quotes around the variables when you use them in the command, to prevent wildcards and whitespace from being interpreted.
protractor indv.js --params.login.username="$argUsername" --params.login.password="$argPassword"
As a general rule, you should always put double quotes around variables unless you know they're not needed.

Related

Visual Studio Code on Windows: How can I pass command line arguments using launch.json?

From the windows command line, I can successfully call my script as follows:
python spot_check.py "stop|CHST SQ_ARRIVAL|2.3" "stop|14 ST_ARRIVAL|2.6" "19:06:28" "19:15:00"
However, if I want to use the VS Code debugger, and I pass the same arguments using the args attribute in launch.json
"args": [
"stop|CHST SQ_ARRIVAL|2.3",
"stop|14 ST_ARRIVAL|2.6" ,
"19:06:28",
"19:15:00",
]
Then I get the following error:
(base) c:\Users\1266143\Desktop\stringlines_ml>cd c:\Users\1266143\Desktop\stringlines_ml && cmd /C "set "PYTHONIOENCODING=UTF-8" && set "PYTHONUNBUFFERED=1" && C:\Users\1266143\AppData\Local\Continuum\anaconda3\python.exe c:\Users\1266143\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\ptvsd_launcher.py --default --client --host localhost --port 61850 c:\Users\1266143\Desktop\stringlines_ml\spot_check.py "stop|CHST SQ_ARRIVAL|2.3" "stop|14 ST_ARRIVAL|2.6" 19:06:28 19:15:00"
'CHST' is not recognized as an internal or external command,
operable program or batch file.
The part that reads 'CHST' is not recognized as an internal or external command, operable program or batch file. leads me to believe that the | is being interpreted as a redirect, rather than as a character in a string literal argument, and the space following CHST means CHST is being interpreted as a command. But why would these arguments evaluate differently on the command line than in Visual Studio? How can I ensure that these arguments are passed correctly to my command line application when in debug mode?
These aren't the quotes you're looking for
You require quotes around your arguments, as shown when running the script/program directly on the command-line (i.e. "stop|CHST SQ_ARRIVAL|2.3")
But in the JSON, the first set of quotes will get stripped off when the JSON is interpreted, so the string "stop|CHST SQ_ARRIVAL|2.3" in the JSON becomes just stop|CHST SQ_ARRIVAL|2.3 before it's fed to later processes.
Then all the arguments get fed to the Command Line or Python interpreter, which will look something like this (although it will likely be a huge line with a bunch of debugging flags and such):
c:/mypath/myfile stop|CHST SQ_ARRIVAL|2.3 stop|14 ST_ARRIVAL|2.6 19:06:28 19:15:00
The quotes you thought you had around the arguments no longer exist. This means that the parser interprets the vertical bar symbol as the "Pipe" command, which tell it that the first command is done, and it should take the output of that command and "pipe" it to the command that follows.
So, the parser thinks you told it to:
Run the command c:/mypath/myfile stop
Take the output of that command and pipe it to the command CHST SQ_ARRIVAL
Pipe the output of that command to the command 2.3 stop
etc.
Since it can't find the command CHST with the argument SQ_ARRIVAL, it gives you the error message you are seeing.
The fix is in
If you want the quotes to end up being passed along as a part of the argument you'll need to layer them. How to do this depends on how the JSON interpreter will handle multiple sets of quotes (I'm not sure how it does).
A few things to try:
Use triple quotes: """stop|CHST SQ_ARRIVAL|2.3""" - in some parsers, when it sees the first quote it starts a string, but if it sees 2 quotes in a row after that, it makes them into a quote inside the string, rather than ending it. So the first and last quote start and end the string, while the other two pairs of quotes will be condensed into a quote on the outside of your argument
Use a backslash in front of the quotes inside the JSON string: "\"stop|CHST SQ_ARRIVAL|2.3\"" - in many parsers the backslash character is an "escape" character and any character immediately after it is considered a string literal that will be put directly into the string, even if it is normally a special character.
Use single quotes inside the string: "'stop|CHST SQ_ARRIVAL|2.3'" - Since Python can use either single or double quotes as a string, normally any arguments going to a python interpreter with single quotes will also be considered a string. However, I'm not sure the arguments will get that far in this case, they will probably be interpreted by the shell first, which likely will not consider single quotes to be the start of a string (but you never know for sure..).
Which method works may depend on what shell you are using (i.e. Windows command prompt, Powershell, Git Bash, sh, c-sh, etc.). Each of them could handle command line interpretation of strings differently.
If none of these works, knowing the root cause, a further search should turn up the answer. Good luck!

bash script pass a variable to a ./configure command containing quotes and expansion

I ham having difficulty understanding how to pass a variable to a ./configure command that includes variable expansion and quotes.
myvars.cfg
myFolderA="/home/myPrefix"
myFolderB="/home/stuffB"
myFolderC="/home/stuffC"
optsA="--prefix=${myFolderA}"
optsB="CPPFLAGS=\"-I${myFolderB} -I${myFolderC}\""
cmd="/home/prog/"
myScript.sh
#!/bin/bash
. /home/myvars.cfg
doCmd=("$cmd/configure" "${optsA}" "${optsB}")
${doCmd[#]}
The doCmd should look like this
/home/prog/configure --prefix=/home/myPrefix CPPFLAGS="-I/home/stuffB -I/home/stuffC"
however it seems when running bash it is adding single quotes
/home/prog/configure --prefix=/home/myPrefix 'CPPFLAGS="-I/home/stuffB' '-I/home/stuffC"'
causing an error of
configure: error: unrecognized option: `-I/home/stuffC"'
Is there a way to pass a variable that needs top be expanded and contains double quotes?
As your script is written, there is no point to using the doCmd array. You could simply write the command:
"$cmd/configure" "${optsA}" "${optsB}"
Or, more simply:
"$cmd/configure" "$optsA" "$optsB"
However, it is possible that you've simplified the script in a way which hides the need for the array. In any case, if you use the array, you need to ensure that its elements are not word-split and filepath expanded, so you must quote its expansion:
"${doCmd[#]}"
Also, you need to get rid of the quotes in optsB. You don't want to pass
CPPFLAGS="-I/home/stuffB -I/home/stuffC"
to the configure script. You want to pass what the shell would pass if you typed the above string. And what the shell would pass would be a single command-line argument with a space in it, looking like this:
CPPFLAGS=-I/home/stuffB -I/home/stuffC
In order to get that into optsB, you just write:
optsB="CPPFLAGS=-I${myFolderB} -I${myFolderC}"
Finally, the shell is not "adding single quotes" into the command line. It is showing you a form of the command whch you could type at the command-line. Since the argument (incorrectly) contains a quote symbol, the shell shows you the command with its arguments skingle-quoted, so that you can see that the optB has been (incorrectly) split into two arguments, each of which contains (incorrectly) one double quote.
You could have found much of the above and more by pasting your script into https://shellcheck.net. As the bash tag summary suggests, you should always try that before asking a shell question here because a lot of the time, it will solve your problem instantly.

Expansion of bash variable in multiple quotes?

I am trying to perform a cURL command within a bash script to POST to a URI. The command requires that one of the arguments be surrounded by double and single quotes i.e. '"jsimmons"' In my script however this argument is a variable so the command keeps failing which I believe is because the variable is doing some weird expansion and the command is losing the quotes necessary.
For my current attempt, which doesn't work, the argument looks like, '""$watcher""' as I am trying to expand the variable and place that string within the double and single quotes.
How can I expand my variable properly to fulfill the requirements of the command?
If you have double quotes around your whole command, you can insert single quotes without any trouble but need to escape double quotes.
For example:
$ watcher=jsimmons
$ echo "'\"$watcher\"'"
'"jsimmons"'
You can escape the surrounding 's and "s with \
\'\"$watcher\"\'

Bash script: need to pass variable expansion result to another script with double quotes

I have an executable compiled from some go code that can be executed as follows:
./goclient -id 10 -env test -args "testarg -testflag_in_args blah blah2"
Essentially, the args flag takes in a long string of multiple arguments, so the input needs to be double quoted as above.
I have another script that executes the aforementioned executable, like this:
./goclient -id 10 -env test -args "${config_options[#]}"
The problem is that after config_options gets expanded, I'm not able to wrap the variable expansion result in double quotes. So the executable thinks that only testarg is passed in as input to -args, and -testflag gets treated as a flag to goclient, which goclient doesn't recognize and complains.
How can I wrap the expansion of "${config_options[#]}" in double quotes to pass to -args? I've tried various things like escaping double quotes around it already. Using eval works, but I've been told not to use it due to security issues. Thanks!

Including "cat" command in unix shell Here Document

I'm trying to create a Here Document which is a shell script that includes the cat command. Of course, it fails when encountering the 2nd cat. I'm performing a lot of substitutions as well, so can't use the "DOC" escape trick.
myfile="/tmp/myipaddr"
cat >/usr/bin/setIPaddress <<_DOC_
...
OUT=`cat $myfile`
...
_DOC_
I supposed I could echo into a file, but that seems kludgy and I have a lot of quotes and backticks I'd need to escape?!? Any other thoughts?
Suppose the file contains
hello world
As written, the script you generate will contain the line
OUT=hello world
because the command substitution is performed immediately.
At the very least, you need to quote the line in the here document as
OUT="`cat $myfile`"
I suspect what you want is to include the literal command substitution in the resulting shell script. To do that, you would want to quote the backticks to prevent them from being evaluated immediately. Better still, use the recommended form of command substitution, $(...), and quote the dollar sign.
cat >/usr/bin/setIPaddress <<_DOC_
...
OUT=\$(cat $myfile)
...
_DOC_
/usr/bin/setIPaddress will then include the line
OUT=$(cat /tmp/myipaddr)

Resources