Escape variable for echo in Bash [duplicate] - bash

This question already has answers here:
I just assigned a variable, but echo $variable shows something else
(7 answers)
Closed 1 year ago.
I have a variable $MOH in Bash which may contain words beginning with minus (-).
I don't want echo to interpret these words as parameters.
For most commands I do it like this:
cmd -- $MOH
But echo does not support --.
So I get a problem in this example:
MOH=-n
echo $MOH
Echo thinks -n is a parameter. But as I said I want to echo the variable as it is.
(Please note that the value of $MOH is not known to me.)
So my question is: How to escape a variable for use in echo?
Also the escape function should be aware of future parameters in echo which are not known yet.
Edit:
Thank you for editing. The question was already asked and the solution is to use printf instead of echo.

It is a known limitation of echo, and actually it is better not to use echo in the first place but rather printf (see below).
Also, beware that there are some quoting issues in your command, one should always use "$MOH" instead of $MOH. Otherwise, "bad things happen" if the variable contains spaces or * characters… For details on this issue, see https://mywiki.wooledge.org/Quotes
Hence the command:
MOH='-n'
printf '%s\n' "$MOH"

Related

Bash variable name expansion in a loop [duplicate]

This question already has answers here:
Bash expand variable in a variable
(5 answers)
Closed 1 year ago.
I have several variables that have the name format of:
var0_name
var1_name
var2_name
And I want to be able to loop thru them in a manner like this:
for i in {0..2}
do
echo "My variable name = " ${var[i]_name}
done
I have tried several different ways to get this expansion to work but have had no luck so far.
Using the ${!prefix*} expansion in bash:
#!/bin/bash
var0_name=xyz
var1_name=asdf
var2_name=zx
for v in ${!var*}; do
echo "My variable name = $v"
# echo "Variable '$v' has the value of '${!v}'"
done
or equivalently, by replacing the for loop with:
printf 'My variable name = %s\n' ${!var*}
You may also consider reading the Shell Parameter Expansion for detailed information on all forms of parameter expansions in bash, including those that are used in the answer as well.

Shell variable unexpected empty in if-then statement after calling sed [duplicate]

This question already has answers here:
How to pass the value of a variable to the standard input of a command?
(9 answers)
Closed 1 year ago.
I have a shell script:
TOPDIR=`pwd`
FOLDER=$($TOPDIR | sed 's/\//\_/g')
if [[ condition ]];then
source ~/[$FOLDER]-build/build-env.sh
fi
the TOPDIR here is /home/uname/project, so the variable FOLDER is supposed to be _home_uname_project because sed is called to replace / with _.
But it goes wrong when executing, terminal tells that /home/uname/[]-build/build-env.sh: No such file or directory which, I guess, means that FOLDER is unexpected empty in the if-then statement. Can anybody help me with figuring this out?
If you look at the output of just
$TOPDIR | sed 's/\//\_/g'
you'll realize that it's empty; it's trying to execute a command equal to the contents of $TOPDIR and pipe the output of that into sed, but there is no output in the first place.
You could do
pwd | sed 's\//_/g'
instead (no need to escape _), which would work.
Or, instead of using an external tool, you could use parameter expansion
topdir="$(pwd)"
topdir="${topdir//\//_}"
with the same result.
Notice that uppercase variable names are discouraged, as they're more likely to clash with existing, reserved names.

Nested quotes in bash -- passing single argument containing spaces [duplicate]

This question already has answers here:
How to substitute quoted, multi-word strings as arguments?
(4 answers)
Closed 7 years ago.
script.sh:
#!/bin/bash
echo "First argument: $1"
wrapper.sh:
#!/bin/bash
CALLER='./script.sh "this should be one argument"'
$CALLER
what happens:
$ ./wrapper.sh
First argument: "this
what I was expecting:
$ ./wrapper.sh
First argument: this should be one argument
I tried different exercises to make it work the way I want it, but I can't find the way to invoke script.sh with single argument containing spaces from within wrapper.sh.
I would also like to understand the way nested quotes are interpreted.
This works instead (only last line changed):
#!/bin/bash
CALLER='./script.sh "this should be one argument"'
eval "$CALLER"
The reason for this is that quoting is applied at a different place in the parsing process than variable substitution, so you need to re-run the result of the substitution ($CALLER) through the parsing process (using eval), but quoted (the "…" around $CALLER) to avoid the field splitting that comes with the substitution already.
Further reading: the POSIX documentation on this, and the links already given in comments.

Exclamation mark inside double quotes results in a strange parse error [duplicate]

This question already has answers here:
Strange behavior of argv when passing string containing "!!!!"
(3 answers)
Closed 5 years ago.
Why does this command line work:
$ output='Irrelevant'; if [[ $output =~ Something ]]; then echo "I found something in the output." ; fi
And this one give me a strange parse error?
$ output='Irrelevant'; if [[ $output =~ Something ]]; then echo "I found something in the output!" ; fi
-bash: !": event not found
The only change from the first version is that the sentence to be echoed inside quotes ends with an exclamation mark. Why does Bash give me that error in the second version?
In case it matters, this is the output from bash --version:
GNU bash, version 4.2.24(1)-release (x86_64-pc-linux-gnu)
You can wrap the string in single quotes instead of double quotes.
The exclamation point invokes the very useful history expansion function described in the bash manual.
History expansions are introduced by the appearance of the history expansion character, which is ! by default. Only \ and ' may be used to escape the history expansion character.
For instance, to execute the last command that started with the word mysql type this:
!mysql
or to execute the last command containing the word grep, type this:
!?grep
The bash manual also documents the syntax of the history expansion operators.

How to use a variable's value as another variable's name in bash [duplicate]

This question already has answers here:
Dynamic variable names in Bash
(19 answers)
Closed 6 years ago.
I want to declare a variable, the name of which comes from the value of another variable, and I wrote the following piece of code:
a="bbb"
$a="ccc"
but it didn't work. What's the right way to get this job done?
eval is used for this, but if you do it naively, there are going to be nasty escaping issues. This sort of thing is generally safe:
name_of_variable=abc
eval $name_of_variable="simpleword" # abc set to simpleword
This breaks:
eval $name_of_variable="word splitting occurs"
The fix:
eval $name_of_variable="\"word splitting occurs\"" # not anymore
The ultimate fix: put the text you want to assign into a variable. Let's call it safevariable. Then you can do this:
eval $name_of_variable=\$safevariable # note escaped dollar sign
Escaping the dollar sign solves all escape issues. The dollar sign survives verbatim into the eval function, which will effectively perform this:
eval 'abc=$safevariable' # dollar sign now comes to life inside eval!
And of course this assignment is immune to everything. safevariable can contain *, spaces, $, etc. (The caveat being that we're assuming name_of_variable contains nothing but a valid variable name, and one we are free to use: not something special.)
You can use declare and !, like this:
John="nice guy"
programmer=John
echo ${!programmer} # echos nice guy
Second example:
programmer=Ines
declare $programmer="nice gal"
echo $Ines # echos nice gal
This might work for you:
foo=bar
declare $foo=baz
echo $bar
baz
or this:
foo=bar
read $foo <<<"baz"
echo $bar
baz
You could make use of eval for this.
Example:
$ a="bbb"
$ eval $a="ccc"
$ echo $bbb
ccc
Hope this helps!
If you want to get the value of the variable instead of setting it you can do this
var_name1="var_name2"
var_name2=value_you_want
eval temp_var=\$$var_name1
echo "$temp_var"
You can read about it here indirect references.
You can assign a value to a variable using simple assignment using a value from another variable like so:
#!/usr/bin/bash
#variable one
a="one"
echo "Variable a is $a"
#variable two with a's variable
b="$a"
echo "Variable b is $b"
#change a
a="two"
echo "Variable a is $a"
echo "Variable b is $b"
The output of that is this:
Variable a is one
Variable b is one
Variable a is two
Variable b is one
So just be sure to assign it like this b="$a" and you should be good.

Resources