How to escape strings in bash script - string

I am running a bash script that calls mysql. The password ist not correctly transmitted, I guess I have to escape some special chars, like the hash or the dollar sign?
#!/bin/bash
USER=myuser
PASS="#mypass$"
# ... call mysql

Using "..." is already the correct thing to do, but the $ needs to be escaped (\$) if it isn't followed by an "invalid" character. However you also need to make sure to always have the variable in quotation marks as well, as in:
somecommand -p "$PASS"

Try to use "\" before the character that you are trying to escape.
#!/bin/bash
USER=myuser
PASS="#mypass\$"
# ... call mysql

Related

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?

escaping hyphen and quotes in expect script

Hello I am using expect to automate a login task.
but the script fails if password starts with a hyphen
How can I escape that
I have a lot of trouble properly escaping ' " or other characters Is there a way I can encode all my characters and send expect the encoded string for it to decode before sending
This is my script
#!/usr/bin/expect -f
spawn ssh -o "PubkeyAuthentication no" -l user 10.10.10.10
expect "password: "
send "-cpass\'ok\r"
expect "$ "
From the man page:
The -- flag forces the next argument to be interpreted as a string rather than a flag. Any string can be preceded by "--" whether
or not it actually looks
like a flag. This provides a reliable mechanism to specify variable strings without being tripped up by those that accidentally
look like flags. (All
strings starting with "-" are reserved for future options.)
Which means you should write your send something like:
send -- "-cpass\'ok\r"
Note: you'll have problems trying to pass any string starting with a hyphen; this won't work: send "-cpass", if your string has a hyphen you need to use -- flag.
You can try to save your password in a variable:
password=-cpass\'ok\r
send "$password"
You simply write a \ in front of every '," or spaces.

Passing multiple variables from local bash to remote bash script without gobbling

I'm having trouble sending multiple variables to a remote bash script without gobbling occurring.
For the sake of this question the variable $timestamp contains 12-12-15 19:45:21
ssh user#serverip "/usr/path/to/script.sh http://www.web.com/$1 http://web.com/$2 $timestamp";
I am sending 3 variables to script.sh
Two URLs with an amended file name in the form of a variable on the end and then my $timestamp variable
But on myscript.sh, when I try to insert $timestamp into a mysql database it only see's the first part of the date before the white space :
12-12-15
So my quotes around the command aren't preventing gobbling. Do I need to quote each variable separately?
ssh user#serverip "/usr/path/to/script.sh http://www.web.com/$1 http://web.com/$2 $timestamp";
This is equivalent to this locally calling
/usr/path/to/script.sh http://www.web.com/$1 http://web.com/$2 $timestamp
Try to quote each individual argument passed
ssh user#serverip "/usr/path/to/script.sh 'http://www.web.com/$1' 'http://web.com/$2' '$timestamp'";
You can also print each argument in the script to see what's being passed... e.g. echo $1, etc.
You can try something like
ssh localhost "printf \"%s %s %s\n\" a b \"last parameter\""
You need to escape the values for the remote host. The correct way of doing this is with printf %q:
ssh user#serverip "/usr/path/to/script.sh \
$(printf "%q " "http://www.web.com/$1" "http://web.com/$2" "$timestamp")"
This works for all variable values. Wrapping them in single quotes would instead result in syntax error and command injection when the variables themselves contain single quotes.

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.

Passing quotes and other special characters literally through bash and ssh

I am trying to run an SSH command that will invoke a script on a remote machine that writes some Lua code to a file.
I have this script command that executes under bash:
ssh bob writelua.sh '{version=1,{["foo"]=17}}'
And writelua.sh looks like this:
echo "return $1" > bar.lua
The end result, however, is that bar.lua has the content:
return version=1
I had thought that single quotes prevented all interpretation. How can I edit the scripts and escaping to pass the raw Lua code through unharmed?
The single quotes prevent interpretation on the local host. The remote host sees the command line
writelua.sh {version=1,{["foo"]=17}}
which is subject to brace expansion. You need a second set of quotes so that the first set of single quotes is passed through to the remote host.
ssh bob writelua.sh "'{version=1,{[\"foo\"]=17}}'"
As you can see, the quotes start to get unwieldy. A better solution is to simply copy a script containing
writelua.sh '{version=1,{["foo"]=17}}'
to the remote host and execute that remotely.
An example using the $'...' quotes:
ssh bob writelua.sh $'{version=1,{[\'foo\']=17}}'
Use heredoc and avoid all the excessive quoting:
ssh -T bob << \EOF
writelua.sh '{version=1,{["foo"]=17}}'
EOF
This will send raw script to remote host and it will get interpreted on the remote host itself.
When it gets too complex, particularly with lots of escaping, I prefer generating the command on a temporary script and execute it locally or remotely via SSH as required.
But there's an alternative: using echo to store the command in a variable and taking advantage of three things:
Single quotes don't do variable expansion and allow double quotes, so you can include something like "$myvar" without escaping $ or "
Double quotes allow variable expansion and single quotes, which means you can include something like animals='all'; echo love $animals to have $animals replaced by its value, and without escaping the '
Strings of both types, i.e. enclosed by single quotes or double quotes, can be concatenated simply by putting them together.
As an example, if I want something like this executed on a remote machine:
source /my-env.sh; perl -MMYLIB::DB -e 'my $t=db_list("name", 1553786458); print "#$t"'
But instead of 1553786458 I want to pass the value from a local variable:
now=`date +%s`
We could have this:
get_list=`echo 'source /my-env.sh; perl -MMYLIB::DB -e' "'my " '$t=db_list("name", ' "$now" '); print "#$t"' "'"`
You can see that single and double quotes are alternated, so we din't have to do any escaping! They don't need to be separated by spaces, but it improves readability and won't affect the result in this case.
And now we can execute:
ssh user#host $get_list
There's still no guarantee that this approach will always work, so once you've built your command, the safest bet would be to copy it over in a file.
If you can use Perl...
use Net::OpenSSH;
my $ssh = Net::OpenSSH->new("bob");
$ssh->system('writelua.sh', '{version=1,{["foo"]=17}}')
or die $ssh->error;
Net::OpenSSH takes care of quoting everything for you.

Resources