just started learning shell script, can't solve this problem - linux

foo=username
bar=foo
a=$(eval echo \$$bar) # same as ${!bar}
echo $(eval echo \$${a^^}) # expected val
How to get the value of foo through the variable bar,
Same as the above output
I know it wants a variable name not a string here.
echo $(eval echo \$${${!bar}^^}) # error bad substitution

I believe this is what you want to start with:
foo=username
bar=$foo
... where username is the literal string, you want to put in the variable, named foo, and $foo is the value of the variable foo, which you want to put in the variable, named bar.
If you want to create another variable, let's say a, which contains the value of bar, you just do:
a=$bar

BASH The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution.
Case conversion is part of parameter and variable expansion. To see the value of the case-converted variable name without assigning another variable you can do:
foo=username
echo \$${foo^^}
$USERNAME
echo $(eval echo \$${foo^^})
stark

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"

Expanding the path stored in a variable [duplicate]

Say I have a folder called Foo located in /home/user/ (my /home/user also being represented by ~).
I want to have a variable
a="~/Foo" and then do
cd $a
I get
-bash: cd: ~/Foo: No such file or directory
However if I just do cd ~/Foo it works fine. Any clue on how to get this to work?
You can do (without quotes during variable assignment):
a=~/Foo
cd "$a"
But in this case the variable $a will not store ~/Foo but the expanded form /home/user/Foo. Or you could use eval:
a="~/Foo"
eval cd "$a"
You can use $HOME instead of the tilde (the tilde is expanded by the shell to the contents of $HOME).
Example:
dir="$HOME/Foo";
cd "$dir";
Although this question is merely asking for a workaround, this is listed as the duplicate of many questions that are asking why this happens, so I think it's worth giving an explanation. According to https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06:
The order of word expansion shall be as follows:
Tilde expansion, parameter expansion, command substitution, and arithmetic expansion shall be performed, beginning to end.
When the shell evaluates the string cd $a, it first performs tilde expansion (which is a no-op, since $a does not contain a tilde), then it expands $a to the string ~/Foo, which is the string that is finally passed as the argument to cd.
A much more robust solution would be to use something like sed or even better, bash parameter expansion:
somedir="~/Foo/test~/ing";
cd "${somedir/#\~/$HOME}"
or if you must use sed,
cd $(echo "$somedir" | sed "s#^~#$HOME#")
If you use double quotes the ~ will be kept as that character in $a.
cd $a will not expand the ~ since variable values are not expanded by the shell.
The solution is:
eval "cd $a"

How to define and print a variable value at the same time in shell

I am facing issue in one bash script as I have print the value of a variable and after then using that variable as an input to another variable but values are not getting print as I understand I have assign value to a variable and then can print.
So I want to know can I define and print a variable value at the same time and store the value to use in another variable within the scope of the function.
For ex.
a="My name is Vikas"
echo "a=My name is Vikas"
b="${a} Singh"
echo "b=${a} Singh"
but I want to do the below
echo "a=My name is Vikas"
echo "b=${a} Singh"
so output should be like
a=My name is Vikas
b=My name is Vikas Singh.
Please help
an assignment can be done while doing an expansion in the case variables are not already set
a= b=
echo "a=${a:=My name is Vikas}"
echo "b=${b:=${a} Singh}"
from manual
${parameter:=word}
If parameter is unset or null, the expansion of word is assigned to parameter. The value of parameter is then substituted. Positional parameters and special parameters may not be assigned to in this way.
a time later, I realized that this could be misleading : it is echo "a=.." which is doing assignment but expansion, which made me understand the question differently, assignments (like any other commands) can be traced with set -x or set -o xtrace (to undo set +x or set +o xtrace) (another similar option set -v or set -o verbose show the command before expansion)
set -x
a="My name is Vikas"
b="${a} Singh"
set +x
will write assignments after expansion to (file descriptor 2) standard error.
You can certainly print the contents of a variable into another variable. The command to print is printf, and the option -v prints to a variable. From the man page:
printf [-v var] format [arguments]
Write the formatted arguments to the standard output under the control of
the format. The -v option causes the output to be assigned to the vari-
able var rather than being printed to the standard output.
So...
$ fname="Vikas"; lname="Singh"
$ printf -v a 'My name is %s' "$fname"
$ printf -v b '%s %s' "$a" "$lname"
$ printf '%s\n%s\n' "$a" "$b"
My name is Vikas
My name is Vikas Singh
But if you want your output to include the variable names, you should probably use declare -p:
$ declare -p a b
declare -- a="My name is Vikas"
declare -- b="My name is Vikas Singh"
By using declare -p, your output may be recycled as input to recreate the same variables in the future.
I think you were trying to do something like this.
b="${a='My name is Vikas'} Singh"
echo $a
echo $b
The command within curly braces { and } sets the variable a in the current shell, and the outer assigment sets b.
Bash manual
EDIT: Actually, as Nauhel pointed out, the variables should not be set. So it should begin with unset a.

Concat 2 variables and use that variable to get value from property file using shell script

I have a property file with below properties,
apache_ip=127.0.0.1
apache_user=root
Now in my shell script i did something like below,
source $1
service=$2 #$2=apache
variable=${service}_ip
serviceIP=${variable}
echo ${serviceIP}
I want to get the output as 127.0.0.1, but the output was apache_ip
I have tried different combination but it dint work. How to concat two variable and use that variable to get the value from property file.
Are you looking for this? I assume you are using bash.
service="apache"
apache_ip="127.0.0.1"
variable="${service}_ip"
ip="${!variable}"
echo "$ip"
which prints 127.0.0.1.
Look here for more information on shell parameter expansion in bash shell.
If the first character of parameter is an exclamation point (!), and
parameter is not a nameref, it introduces a level of variable
indirection. Bash uses the value of the variable formed from the rest
of parameter as the name of the variable; this variable is then
expanded and that value is used in the rest of the substitution,
rather than the value of parameter itself. This is known as indirect
expansion. If parameter is a nameref, this expands to the name of the
variable referenced by parameter instead of performing the complete
indirect expansion.
When you want to get the values from the config file, you can use grep:
configfile=$1
service=$2
serviceIP=$(grep "^${service}_ip=" configfile|cut -d= -f2-)
echo "serviceIP=${serviceIP}"
You can do about the same when the configfile has been sourced:
serviceIP=$(set | grep "^${service}_ip=" |cut -d= -f2-)
echo "serviceIP=${serviceIP}"

How is Bash interpreting these statements? [duplicate]

This question already exists:
Assign and use of a variable in the same subshell [duplicate]
Closed 7 years ago.
$ a=one; echo $a
one
$ a=two echo $a
one
$ echo $a
one
The value of a will be initialized to 'two' but why is it displaying 'one'?
Same line initialization of env variables is only available for sub shells.
It will be more evident from these examples:
unset a
a=two echo "<$a>"
<>
a=two bash -c 'echo "<$a>"'
<two>
echo "<$a>"
<>
In the 2nd snippet it prints <two> because we're spawning a sub-shell using bash -c.
This is due to the order in which the shell processes substitutions and variables. According to POSIX rules for a shell:
When a given simple command is required to be executed (that is, when
any conditional construct such as an AND-OR list or a case statement
has not bypassed the simple command), the following expansions,
assignments, and redirections shall all be performed from the
beginning of the command text to the end:
The words that are recognized as variable assignments or redirections according to Shell Grammar Rules are saved for processing
in steps 3 and 4.
The words that are not variable assignments or redirections shall be expanded. If any fields remain following their expansion, the first
field shall be considered the command name and remaining fields are
the arguments for the command.
Redirections shall be performed as described in Redirection.
Each variable assignment shall be expanded for tilde expansion, parameter expansion, command substitution, arithmetic expansion, and
quote removal prior to assigning the value.
That means that the variable assignment is performed after parameter expansion has occurred, e.g. $a is expanded before the a= variable assignment for that command has been processed. The new value of a will be passed into the execution environment of the command but it won't be of any use in this case with echo.
You can perhaps see better what's going on if you use a variable that does not already exist.
$ unset a
$ a=two echo \($a\)
()
$ a=one
$ a=two echo \($a\)
(one)
Here's an example where you can see that the variable assignment is passed to the execution environment of the command that is executed:
$ a=one
$ a=two python -c 'import os;print(os.environ["a"])'
two

Resources