Pass quoted arguments to shell script and maintain quoting [duplicate] - linux

This question already has answers here:
How do I pass on script arguments that contain quotes/spaces?
(2 answers)
Closed 2 years ago.
I'm attempting to re-use parameters sent to my script as parameters for a command I execute within my script. See example below where I execute mailx.
bash
$./myscript.sh "My quoted Argument"
myscript.sh
mailx -s $1
This ends up being executed as: mailx -s My Quoted Argument.
I tried "$1", but my quotes are thrown away. (Incorrect statement, read answer below)
I tried ""$1"" but my quotes are thrown away.
I tried to do '$1' but that's strong quoting so $1 never gets interpreted.
I realize I can do $#, but that gives me every param.
.... you get the picture
Any help would be appreciated!

mailx -s "$1" correctly passes the value of $1 to mailx as-is, embedded spaces and all.
In the case at hand, this means that My Quoted Argument is passed as a single, literal argument to mailx, which is probably your intent.
In a shell command line, quotes around string literals are syntactic elements demarcating argument boundaries that are removed by the shell in the process of parsing the command line (a process called quote removal).
If you really wanted to pass embedded double-quotes (which would be unusual), you have 2 options:
either: embed the quotes on invocation ./myscript.sh "\"My quoted Argument\""
or: embed the quotes inside myscript.sh: mailx -s "\"$1\""

You may just put escaped quotes around $1 in your script
mailx -s \"$1\"

Can you try passing the argument like this
$./myscript.sh \"My quoted Argument\"?

Related

linux bash, passing paramenters using a varible issue

I am trying to use a variable to store the parameters, here is the simple test:
#!/bin/bash
sed_args="-e \"s/aaaa/bbbb/g\""
echo $sed_args`
I expected the output to be
-e "s/aaaa/bbbb/g"
but it gives:
"s/aaaa/bbbb/g"
without the "-e"
I am new to bash, any comment is welcome. Thanks, maybe this is already answered somewhere.
You need an array to construct arguments dynamically:
#!/usr/bin/env bash
sed_args=('-e' 's/aaaa/bbbb/g')
echo "${sed_args[#]}"
When you use the variable without double quotes, it gets word split by the shell even before echo sees the value(s). Then, the bash's builtin echo interprets -e as a parameter for itself (which is normally used to turn on interpretation of backslash escapes).
When you double quote the variable, it won't be split and will be interpreted as a single argument to echo:
echo "$sed_args"
For strings you don't control, it's safer to use printf as it doesn't take any arguments after the format string:
printf %s "$string"

bash echo environment variable containing escaped characters

I have an script that echo the input given, into a file as follows:
echo $# > file.txt
When I pass a sting like "\"" I want it to exactly print "\"" to the file however it prints ".
My question is how can I print all characters of a variable containing a string without considering escapes?
When I use echo in bash like echo "\"" it only prints " while when I use echo '"\""' it prints it correctly. I thought maybe that would be the solution to use single quotes around the variable, however I cannot get the value of a variable inside single quotes.
First, note that
echo $# > file.txt
can fail in several ways. Shellcheck identifies one problem (missing quotes on $#). See the accepted, and excellent, answer to Why is printf better than echo? for others.
Second, as others have pointed out, there is no practical way for a Bash program to know exactly how parameters were specified on the command line. For instance, for all of these invocations
prog \"
prog "\""
prog '"'
the code in prog will see a $1 value that consists of one double-quote character. Any quoting characters that are used in the invocation of prog are removed by the quote removal part of the shell expansions done by the parent shell process.
Normally that doesn't matter. If variables or parameters contain values that would need to be quoted when entered as literals (e.g. "\"") they can be used safely, including passing them as parameters to other programs, by quoting uses of the variable or parameter (e.g. "$1", "$#", "$x").
There is a problem with variables or parameters that require quoting when entered literally if you need to write them in a way that they can be reused as shell input (e.g. by using eval or source/.). Bash supports the %q format specification to the printf builtin to handle this situation. It's not clear what the OP is trying to do, but one possible solution to the question is:
if (( $# > 0 )) ; then
printf -v quoted_params '%q ' "$#" # Add all parameters to 'quoted_params'
printf '%s\n' "${quoted_params% }" # Remove trailing space when printing
fi >file.txt
That creates an empty 'file.txt' when no positional parameters are provided. The code would need to be changed if that is not what is required.
If you run echo \", the function of the backslash in bash is to escape the character after it. This actually enables you to use the double quotes as an argument. You cannot use a backslash by itself; if you want to have a backslash as an argument you need to use another slash to escape that: echo \\
Now if you want to create a string where these things are not escaped, use single quotes: echo '\'
See for a better explanation this post: Difference between single and double quotes in Bash

Quote argument strings Shell

Can I quote arguments that have spaces or special chars in the command line? If not, how is this handled. We have one argument that is a multiword string. I'm sure this has been asked many times, but I cant find it.
./myscript name=bob occupation=guy who does stuff
You can use quotes. Something like:
$ var='abc def'
$ echo "$var"
abc def
You can read more here.
Your case example (note I'm calling the script that needs the multiword string from the another script in this example):
sh ./test.sh 'this is a test'
test.sh contains echo $1 and prints this is a test. Hope this solution works.

Why does bash insert additional quotes

I need to pipe an expression including single quotes to a command, but bash inserts loads of extra quotes which breaks my command. As a really simple example take:
#!/bin/bash -x
echo 'EXPRESSION' | more
which gives:
+ echo EXPRESSION
+ more
EXPRESSION
As I want the single quotes to be displayed, I must escape them:
#!/bin/bash -x
echo \'EXPRESSION\' | more
Which now gives me:
+ echo ''\''EXPRESSION'\'''
+ more
'EXPRESSION'
So within the script, I get this bizarre ''\''EXPRESSION'\''' thing. The command I am piping the expression to is an executable that interacts with a document management system, and expects a specific format—which includes single quotes around EXPRESSION and not ''\'' and '\'''.
Is there any way to stop bash from adding the additional quotes and backslashes? I've messed around with strings and eval etc., but have failed to get rid of those additional quotes.
You can also try it with double quotes like this,
echo "'EXPRESSION'"|more
Output will be,
'EXPRESSION'
The /bin/bash -x is producing the top 2 lines. Your code produces the 3rd line. If you want you can just remove the -x and you should see it in a better way.
The above answer from Skynet works just fine, but with the -x option, it still shows 3 lines. It's just what the -x does.

Setting a Variable = to a string in a text file

I am trying to place a line of a text file, directly in a mail function. The string has the ' ' around it in the text file.
mailx -s "New Member" "cat ../address"
A line in ../address is 'my-email#gmail.com' including the ' ' quotes.
The cat ../address is not the best way of doing it but I do not know any other way to try.
Required result should be:
mailx -s "New Member" 'my-email#gmail.com'
You need to remove the literal ' chars. from the line in order for the address to be passed correctly to mailx:
There's more than one way to do it:
mailx -s "New Member" "$(tr -d "'" < ../address)"
mailx -s "New Member" "$(xargs < ../address)"
Note: The above assumes that ../address contains only 1 line.
#chepner makes an important point:
storing the quotes in the file and then reading them in [and using the result unquoted] is not the same as quoting the command substitution.
To elaborate on this further:
The OP shows 'my-email#gmail.com' as the desired argument to pass to mailx. In this direct form of single-quoting, bash will remove the quotes (see Quote Removal section in man bash) before handing the - unexpanded - string contents, without the quotes, to mailx.
Indirect quoting does NOT work: Reading in a string that happens to contain literal quote characters around it is NOT subject to quote removal by bash, so the enclosing quotes are passed through as part of the string - mailx would see an invalid email address that starts (and ends) with a '.
Therefore, the solution is:
remove the quotes from the input string first
then use direct quoting to protect the result from (further) shell expansion; note that double-quoting is needed so as to make sure the command substitution (($...)) is evaluated.
Use backticks for command substitution. I assume there is only one line in the file.
mailx -s "New Member" `cat ../address`
An alternative/better form for backticks is $()
mailx -s "New Member" $(cat ../address)

Resources