Setting a Variable = to a string in a text file - string

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)

Related

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

How to extract string between quotes in Bash

I need to extract the string between quotation marks in a file.
For example: my file is called test.txt and it has the following content:
"Hello_World"
I am reading it as follows from bash:
string="$(head -1 test.txt)"
echo $string
This prints "Hello_World", but I need Hello_World.
Any help will be appreciated. Thanks.
You can do this in pure bash without having to spawn any external programs:
read -r line < test.txt ; line=${line#\"} ; line=${line%\"} ; echo $line
The read actually reads in the entire line, and the two assignments actually strip off any single quote at the start or end of the line.
I assumed you didn't want to strip out any quotes within the string itself so I've limited it to one at either end.
It also allows you to successfully read lines without a leading quote, trailing quote, or both.
You can use tr:
echo "$string " | tr -d '"'
From man tr:
DESCRIPTION
The tr utility copies the standard input to the standard output with substitution or deletion of selected characters.
The following options are available:
-C Complement the set of characters in string1, that is ``-C ab'' includes every character except for `a' and `b'.
-c Same as -C but complement the set of values in string1.
-d Delete characters in string1 from the input.
You can simply use sed to read the first line and also filter out ", try following command,
sed -n '1 s/"//gp' test.txt
Brief explanation,
-n: suppress automatic print
1: Match only the first line
s/"//gp: filter out ", and then print the line

Unexpected End Of File Error for invalid line number [duplicate]

I need my script to send an email from terminal. Based on what I've seen here and many other places online, I formatted it like this:
/var/mail -s "$SUBJECT" "$EMAIL" << EOF
Here's a line of my message!
And here's another line!
Last line of the message here!
EOF
However, when I run this I get this warning:
myfile.sh: line x: warning: here-document at line y delimited by end-of-file (wanted 'EOF')
myfile.sh: line x+1: syntax error: unexpected end of file
...where line x is the last written line of code in the program, and line y is the line with /var/mail in it. I've tried replacing EOF with other things (ENDOFMESSAGE, FINISH, etc.) but to no avail. Nearly everything I've found online has it done this way, and I'm really new at bash so I'm having a hard time figuring it out on my own. Could anyone offer any help?
The EOF token must be at the beginning of the line, you can't indent it along with the block of code it goes with.
If you write <<-EOF you may indent it, but it must be indented with Tab characters, not spaces. So it still might not end up even with the block of code.
Also make sure you have no whitespace after the EOF token on the line.
The line that starts or ends the here-doc probably has some non-printable or whitespace characters (for example, carriage return) which means that the second "EOF" does not match the first, and doesn't end the here-doc like it should. This is a very common error, and difficult to detect with just a text editor. You can make non-printable characters visible for example with cat:
cat -A myfile.sh
Once you see the output from cat -A the solution will be obvious: remove the offending characters.
Please try to remove the preceeding spaces before EOF:-
/var/mail -s "$SUBJECT" "$EMAIL" <<-EOF
Using <tab> instead of <spaces> for ident AND using <<-EOF works fine.
The "-" removes the <tabs>, not <spaces>, but at least this works.
Note one can also get this error if you do this;
while read line; do
echo $line
done << somefile
Because << somefile should read < somefile in this case.
May be old but I had a space after the ending EOF
<< EOF
blah
blah
EOF <-- this was the issue. Had it for years, finally looked it up here
For anyone stumbling here who googled "bash warning: here-document delimited by end-of-file", it may be that you are getting the
warning: here-document at line 74 delimited by end-of-file
...type warning because you accidentally used a here document symbol (<<) when you meant to use a here string symbol (<<<). That was my case.
Here is a flexible way to do deal with multiple indented lines without using heredoc.
echo 'Hello!'
sed -e 's:^\s*::' < <(echo '
Some indented text here.
Some indented text here.
')
if [[ true ]]; then
sed -e 's:^\s\{4,4\}::' < <(echo '
Some indented text here.
Some extra indented text here.
Some indented text here.
')
fi
Some notes on this solution:
if the content is expected to have simple quotes, either escape them using \ or replace the string delimiters with double quotes. In the latter case, be careful that construction like $(command) will be interpreted. If the string contains both simple and double quotes, you'll have to escape at least of kind.
the given example print a trailing empty line, there are numerous way to get rid of it, not included here to keep the proposal to a minimum clutter
the flexibility comes from the ease with which you can control how much leading space should stay or go, provided that you know some sed REGEXP of course.
When I want to have docstrings for my bash functions, I use a solution similar to the suggestion of user12205 in a duplicate of this question.
See how I define USAGE for a solution that:
auto-formats well for me in my IDE of choice (sublime)
is multi-line
can use spaces or tabs as indentation
preserves indentations within the comment.
function foo {
# Docstring
read -r -d '' USAGE <<' END'
# This method prints foo to the terminal.
#
# Enter `foo -h` to see the docstring.
# It has indentations and multiple lines.
#
# Change the delimiter if you need hashtag for some reason.
# This can include $$ and = and eval, but won't be evaluated
END
if [ "$1" = "-h" ]
then
echo "$USAGE" | cut -d "#" -f 2 | cut -c 2-
return
fi
echo "foo"
}
So foo -h yields:
This method prints foo to the terminal.
Enter `foo -h` to see the docstring.
It has indentations and multiple lines.
Change the delimiter if you need hashtag for some reason.
This can include $$ and = and eval, but won't be evaluated
Explanation
cut -d "#" -f 2: Retrieve the second portion of the # delimited lines. (Think a csv with "#" as the delimiter, empty first column).
cut -c 2-: Retrieve the 2nd to end character of the resultant string
Also note that if [ "$1" = "-h" ] evaluates as False if there is no first argument, w/o error, since it becomes an empty string.
make sure where you put the ending EOF you put it at the beginning of a new line
Along with the other answers mentioned by Barmar and Joni, I've noticed that I sometimes have to leave a blank line before and after my EOF when using <<-EOF.

Double /Single quote syntax

When querying a list and putting the value in a variable and trying to use the variable in another script it doenst get the format needed.
script 1:
cilist=$(opr-ci-list.sh -view_name TN_UD_REFRESH_MRE | sed -e '/^[TL-]/d' -e '/^\s*$/d' -e 's/^....//' | awk -vORS=, '{ print $1 }' | sed 's/,$/\n/')
The output of this script will be ID's comma seperated string like: 7c553435c1376c8f5f020fcee0b8ef51,7d427dd75235bf513286d3210e1bd787
echo $cilist
7c553435c1376c8f5f020fcee0b8ef51,7d427dd75235bf513286d3210e1bd787
=> no quotes to be seen when doing a echo
script 2:
opr-downtime.sh -cis "\"$cilist\""
i receive an error because the are single quotes surrounding the variable:
-cis '"7c553435c1376c8f5f020fcee0b8ef51,7d427dd75235bf513286d3210e1bd787 "'
I tried several syntax ways but keep getting the wrong input for the second script. Or i have no quotes or quotes like '" in front and behind.
Any help or feedback on the correct syntax would be appreciated.
The shell treats the quote characters as special characters. For double quote ("), it treats the enclosed data as a single argument to the command. This would be useful if the input had a space (or other shell separator token) within it. However, when the argument is provided to the command, the quote is removed.
You can try using backslash (\) to escape the double quote. But, you may still want to enclose everything with a double quote incase $cilist has input that requires quoting.
script.sh -cis "\"$cilist\""

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

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\"?

Resources