evaluating a string as a partial bash command - string

I'm writing a script in bash that reads this line from a file next-version=2.0 and I want to extract the 2.0. I can parse it as an array and split it on the =, but that feels like overkill. If I run export $VERSION which logically should become export next-version=2.0 which I could then dereference with $next-version. Instead I get bash: export: `next-version=2.0': not a valid identifier
So I tried VERSION="export $VERSION" which evaluates to export next-version=2.0 GREAT, so when I run eval $VERSION or $VERSION i get the same error. I think the next-version=2.0 is somehow maintaining the fact that it's a string? I thought it might just be upset that it's reading from lowercase, but when I repeat the process with NEXT-VERSION same result.

A function or command name in bash can contain a -, but not a parameter name. This means next-version=2.0 is not a valid assignment in bash, because the string before the = must be a valid name. The only thing you can do is parse it as you described, although there is no need for an array.
IFS== read -r name value <<< "$str"
or
value="${str#*=}" # Strip the prefix up to and including the first =

It's the -
trying $
export STRING-SS=asd
bash: export: `STRING-SS=asd': not a valid identifier
change next-version to NEXTVERSION, NEXT_VERSION, next_version or nextversion.

Related

Indirect expansion returns variable name instead of value

I am trying to set up some variables using indirect expansion. According to the documentation I've read, the set up should be simple:
var1=qa
qa_num=12345
varname="${var1}_ci"
echo ${!varname}
I should be getting "12345". Instead, the output is "varname". If I remove the exclamation point, I end up with "qa_ci", not "12345"
This should be a relatively simple solution, so I'm not sure what I'm missing, if anything.
Your code defines qa_num, but the varname assignment references qa_ci. As a result, your echo was expanding nonexistent qa_ci, giving empty results. Changing the varname assignment fixes the problem on my system.
Example: foo.sh:
#!/bin/bash
var1=qa
qa_num=12345
varname="${var1}_num" # <=== not _ci
echo "${!varname}" # I also added "" here as a general good practice
Output:
$ bash foo.sh
12345

bash variable in string substitution

I am trying to do string substitution in bash, want to understand it better.
I crafted a success case like this:
a=abc_de_f
var=$a
echo ${var//_/-}
outout is abc-de-f. This works.
However, the following script fails:
a=abc_de_f
echo ${$a//_/-}
The error message is ${$a//_/-}: bad substitution.
It seems like related to how we can use a variable in substitution. Why this fails? How bash handles variables in this case?
Also, what is the best practice to handle escape characters in bash string substitution?
In the second case, you don't need the second $ as a is the string.
a=abc_de_f
echo ${a//_/-}
If you wanted to add a level of indirection, you can use ! before the variable as in
a=abc_de_f
b=a
echo ${b//_/-}
will output a, while
echo ${!b//_/-}
will output abc-de-f.
See here for a discussion on the art of escaping in BASH

dynamically creating bash variable and accessing its value defined earlier

i am trying to read the value of a bash variable defined earlier , but this variable name derived dynamically.
this is the bash script i am trying to do
$ mythreshold=10
$ table=my
$ threshold="$table"threshold
$ echo $("$threshold")
mythreshold
but when i try to read this variable value like
$ echo $("$threshold")
-bash: mythreshold: command not found
however i was expecting it to print
$ echo $("$threshold")
10
is there a way i can get this work, it should have printed the value of mythreshold variable defined above
$() is Command Substitution. It runs the command inside and returns the output. A variable name is not a command.
You can $(echo "$threshold") but that will only get the mythreshold back.
You need indirection for what you want. Specifically Evaluating indirect/reference variables.
As an example, for this specific case:
echo "${!threshold}"
Use eval command :
eval echo \${$threshold}
More details about this command can be found here:
eval command in Bash and its typical uses

Shell Variables are empty when called in a file name but not when echo'd or called elsewhere

I have 4 shell variables set
remote_account="raccname"
remote_machine="server"
First_Name="firstname"
Last_Name="lastname"
when I call remote_account or remote_machine in my script they get used fine
echo "What directory shall you choose?"
read dir
scp -r ~/csc60/$dir $remote_account#$remote_machine:directoryA
exit;;
but when I call the other two as such
echo "What directory shall you choose?"
read dir
scp $remote_account#$remote_machine:tars/$Last_Name_$First_Name_$dir.tar.z ~/tars
exit;;
it grabs the tars file from tars/$dir.tar.z completely skipping $Last_Name_$First_Name_
when I throw an echo $Last_Name in it still shows it as "lastname"
Is there some rule using "_" between variables or something, or am I just missing something obvious?
_ is a valid character for variable names, therefore you have to qualify which part is the variable.
scp "$remote_account#$remote_machine:tars/${Last_Name}_${First_Name}_$dir.tar.z" ~/tars
You need to delimit your variable value using ${}, as you declared $Last_Name_$First_Name_$dir is treated as one variable and shell put value for it. As in your case you did not defined value for it . It will be intepreted as "".
use ${LAST_NAME}_${FIRST_NAME}

Can colon be used as identifier?

I saw a code in The Bash command :(){ :|:& };: will spawn processes to kernel death. Can you explain the syntax? as follows
user#host$ :(){ :|:& };:
Here colon used as identifier for function name.
Can colon be used as identifier?
Yes, it can.
$ :()
> {
> echo "hello from : :)"
> }
$ :
hello from : :)
According to the documentation:
name
A word consisting solely of letters, numbers, and underscores, and beginning with a letter or underscore. Names are used as shell variable and function names. Also referred to as an identifier.
No, the colon is not valid in function names. So either the bomb doesn't work in bash, or the documentation is failing.
I shortly thought that the colon might refer to the built-in operator, but I don't see how that could get the expected semantics.
The implementation seems to be inconsistent. You can define and call a function containing colons and Google even suggests this for packages in their style guide.
Though I noticed you can not export nor unset these functions.
#!/usr/bin/env bash
foo:bar() {
echo "foo:bar called"
}
foo:bar
export -f foo:bar
unset foo:bar
The export won't complain but if you call another bash script afterwards foo:bar is not available.
The unset will even trigger an error:
/foo/bar: line 11: unset: `foo:bar': not a valid identifier
$ bash --version
GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu)

Resources