Strange shell behaviour - shell

Here is a simple bash script:
a="asd"
b="qf"
echo "$a.$b"
echo "$a_$b"
It's output is:
asd.qf
qf
Why the second line is not "asd_qf" but "qf"?

Because you haven't defined a variable named a_. For that second printout to work, use:
echo "${a}_$b"

Your second echo displays the value of variable $a_ which is unset.
Use echo "${a}_$b"

The shell has rules about what can go in a variable name, and $a_ is interpreted as the variable named a_ (there is no variable with that name so its value is empty).
You can always add braces to be explicit. In this case, ${a}_$b will clearly identify what the variable name is and the result will be what you expect.

Related

Reassign value of $1 in bash

I'm trying to reassign the value of the positional command line argument $1 to another variable to use elsewhere in the script, but it never works. I have put the following code in a new script and found that the value of the new variable is always blank.
dirname = $1
echo "This is \$1:$1"
echo "This is \$dirname:$dirname"
The output of this after running ./test.sh someval is:
This is $1:someval
This is $dirname:
As you can see, 'dirname' is blank, even after being assigned the value of $1. I'm new to bash so likely missing something. Any help is appreciated.
Assignments cannot have whitespace around the =. An assignment is a single word containing a =: the name precedes the (first) =, and the value follows it.
dirname=$1

Bash: Combine creating a file and storing the Path in a variable

Is there a way to create a file and store the path into a variable in Bash?
ENV_FILE=./.projects.env
echo > $ENV_FILE
How can I achieve this in one command?
Edit:
From the suggestions in the comments below, it could be done like so:
ENV_FILE=$(> ./.projects.env && echo './.projects.env')
If ENV_FILE is not already set, you can use this:
echo > "${ENV_FILE:=./.projects.env}"
Note: if ENV_FILE is already set to a non-null value, this will leave it unchanged and use its existing value. From the Parameter Expansion section of the bash man page:
${parameter:=word}
Assign Default Values. 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.
BTW, using echo this way will not fully erase the file, it'll replace its contents with a newline (essentially, a single blank line). For a truly empty file, just don't use any command:
> "${ENV_FILE:=./.projects.env}"
You can try
FILE_NAME=<a file name>
ENV_FILE=$(touch "$FILE_NAME" && realpath "$FILE_NAME")
replace <a file name> with the the name you want to give.
if you don't want to repeat the filename (and eliminate potential typos), you can do this instead...
ENV_FILE=$(> ./.projects.env && echo !$)

Bash assignment value to variable as command substitution and print value output

I would like to achieve this in Bash: echo $(a=1)and print the value of variable a
I test eval, $$a,{}, $() but none of them work as most of the times either I got literally a=1 or in one case (I don't remember which) it tried to execute the value.
I known that I can do: a=1;echo $a but because I'm little fun one command per line (even if sometimes is getting little complicated) I was wondering if is possible to do this either with echo or with printf
If you know that $a is previously unset, you can do this using the following syntax:
echo ${a:=1}
This, and other types of parameter expansion, are defined in the POSIX shell command language specification.
If you want to assign a numeric value, another option, which doesn't depend on the value previously being unset, would be to use an arithmetic expansion:
echo $(( a = 1 ))
This assigns the value and echoes the number that has been assigned.
It's worth mentioning that what you're trying to do cannot be done in a subshell by design because a child process cannot modify the environment of its parent.

Insert variable value or default value if empty in a string

I want to insert the value of an environment variable in a string or a default value if the corresponding variable is not initialized.
Example:
if [ -z $MY_VAR ];
then
MY_VAR="default"
fi
echo "my variable contains $MY_VAR"
I'm however using a lot of variables in my strings and the tests are cluttering my script.
Is there a way to make a ternary expression in my string?
Example of what I want to achieve (it doesn't work):
echo "my variable contains ${-z $MY_VAR ? $MY_VAR : 'default'}"
To actually set the value of the variable, rather than just expanding to a default if it has no value, you can use this idiom:
: ${MY_VAR:=default}
which is equivalent to your original if statement. The expansion has the side effect of actually changing the value of MY_VAR if it is unset or empty. The : is just the do-nothing command which provides a context where we can use the parameter expansion, which is treated as an argument that : ignores.
See Bash Default Values
→ echo "my variable contains ${MY_VAR:-default}"
my variable contains default

concatenate variables in a bash script

Hi I would like to set a variable by concatenating two other variables.
Example
A=1
B=2
12=C
echo $A$B
desired result being C
however the answer I get is always 12
Is it possible?
UPDATED
Example
A=X
B=Y
D=$A$B
xy=test
echo $D
desired result being "test"
It looks like you want indirect variable references.
BASH allows you to expand a parameter indirectly -- that is, one variable may contain the name of another variable:
# Bash
realvariable=contents
ref=realvariable
echo "${!ref}" # prints the contents of the real variable
But as Pieter21 indicates in his comment 12 is not a valid variable name.
Since 12 is not a valid variable name, here's an example with string variables:
> a='hello'
> b='world'
> declare my_$a_$b='my string'
> echo $my_hello_world
my string
What you are trying to do is (almost) called indirection: http://wiki.bash-hackers.org/syntax/pe#indirection
...I did some quick tests, but it does not seem logical to do this without a third variable - you cannot do concatenated indirection directly as the variables/parts being concatenated do not evaluate to the result on their own - you would have to do another evaluation. I think concatenating them first might be the easiest. That said, there is a chance you could rethink what you're doing.
Oh, and you cannot use numbers (alone or as the starting character) for variable names.
Here we go:
cake="cheese"
var1="ca"
var2="ke"
# this does not work as the indirection sees "ca" and "ke", not "cake". No output.
echo ${!var1}${!var2}
# there might be some other ways of tricking it to do this, but they don't look to sensible as indirection probably needs to work on a real variable.
# ...this works, though:
var3=${var1}${var2}
echo ${!var3}

Resources