How to construct a comma-separated string in Bourne shell? - string

I'm not sure how to do this but I figured I would ask here.. I'm trying to create a string of specific environment variables such that:
$A = "foo"
$B = "bar"
$C = "baz"
would give "foo, bar, baz"
Unfortunately, it doesn't seem that the Bourne shell supports arrays, which would have made these easily solvable. The other way I'm trying to solve this is by directly inserting my own variable called $COMMA after each environment variable, however I am getting syntax errors so I'm not sure how to do this correctly. Would appreciate any advice here, thanks!

Your variables shouldn't start with $ unless you want the value of them (this isn't perl or php...)
A=foo
B=bar
C=baz
echo $A,$B,$C
or even:
A=foo B=bar C=baz echo $A,$B,$C
will give you a comma seperated list of the variables you defined.

Related

Evaluate a string read from a file in perl

Made up example (perl):
my $x = read_input_from_file();
# $x now contains string $ENV{SOMETHING}/dir/$ENV{SOMETHING_ELSE}
my $y = eval($x); # doesnt work
How can I get value of string contained in $x in the script?
So far I have tried using eval which doesn't generate any output. I am hoping that something already exists in perl and these string expressions do not need to be parsed and evaluated.
The "string" eval is a little specific:
eval in all its forms is used to execute a little Perl program.
...
In a string eval, the value of the expression (which is itself determined within scalar context) is first parsed, and if there were no errors, executed as a block within the lexical context of the current Perl program.
So this evaluates code, and with a variable to be evaluated containing a string literal we have a "bareword" ("Unquoted string") which is generally no good. In your case, those / in $x cause additional trouble.
If the content of the variable to evaluate is a string literal (not code) it need be quoted
my $y = eval q(") . $x . q("); # double-quote so that it interpolates
I use the operator form of a single quote, q(). Quoted under it is a double-quote since $x itself seems to contain variables that need be evaluated (interpolated).
Keep in mind that running code from external sources can be a serious security problem.

In Bash, is there a way to expand variables twice in double quotes?

For debugging my scripts, I would like to add the internal variables $FUNCNAME and $LINENO at the beginning of each of my outputs, so I know what function and line number the output occurs on.
foo(){
local bar="something"
echo "$FUNCNAME $LINENO: I just set bar to $bar"
}
But since there will be many debugging outputs, it would be cleaner if I could do something like the following:
foo(){
local trace='$FUNCNAME $LINENO'
local bar="something"
echo "$trace: I just set bar to $bar"
}
But the above literally outputs:
"$FUNCNAME $LINENO: I just set bar to something"
I think it does this because double quotes only expands variables inside once.
Is there a syntactically clean way to expand variables twice in the same line?
You cannot safely evaluate expansions twice when handling runtime data.
There are means to do re-evaluation, but they require trusting your data -- in the NSA system design sense of the word: "A trusted component is one that can break your system when it fails".
See BashFAQ #48 for a detailed discussion. Keep in mind that if you could be logging filenames, that any character except NUL can be present in a UNIX filename. $(rm -rf ~)'$(rm -rf ~)'.txt is a legal name. * is a legal name.
Consider a different approach:
#!/usr/bin/env bash
trace() { echo "${FUNCNAME[1]}:${BASH_LINENO[0]}: $*" >&2; }
foo() {
bar=baz
trace "I just set bar to $bar"
}
foo
...which, when run with bash 4.4.19(1)-release, emits:
foo:7: I just set bar to baz
Note the use of ${BASH_LINENO[0]} and ${FUNCNAME[1]}; this is because BASH_LINENO is defined as follows:
An array variable whose members are the line numbers in source files where each corresponding member of FUNCNAME was invoked.
Thus, FUNCNAME[0] is trace, whereas FUNCNAME[1] is foo; whereas BASH_LINENO[0] is the line from which trace was called -- a line which is inside the function foo.
Although eval has its dangers, getting a second expansion is what it does:
foo(){
local trace='$FUNCNAME $LINENO'
local bar="something"
eval echo "$trace: I just set bar to $bar"
}
foo
Gives:
foo 6: I just set bar to something
Just be careful not to eval anything that has come from external sources, since you could get a command injected into the string.
Yes to double expansion; but no, it won't do what you are hoping for.
Yes, bash offers a way to do "double expansion" of a variable, aka, a way to first interpret a variable, then take that as the name of some other variable, where the other variable is what's to actually be expanded. This is called "indirection". With "indirection", bash allows a shell variable to reference another shell variable, with the final value coming from the referenced variable. So, a bash variable can be passed by reference.
The syntax is just the normal braces style expansion, but with an exclamation mark prepended to the name.
${!VARNAME}
It is used like this:
BAR="my final value";
FOO=BAR
echo ${!FOO};
...which produces this output...
my final value
No, you can't use this mechanism to do the same as $( eval "echo $VAR1 $VAR2" ). The result of the first interpretation must be exactly the name of a shell variable. It does not accept a string, and does not understand the dollar sign. So this won't work:
BAR="my final value";
FOO='$BAR'; # The dollar sign confuses things
echo ${!FOO}; # Fails because there is no variable named '$BAR'
So, it does not solve your ultimate quest. None-the-less, indirection can be a powerful tool.

Bash - Creating a string with a string variable

I have a variable called CURRENTDATE=20151105.
I want to create a string as below:
abc_20151105_20151105
I tried the following variations:
echo "abc_$CURRENTDATE_$CURRENTDATE"
This gave abc_20151105
echo "abc_'$CURRENTDATE'_'$CURRENTDATE'"
This gave abc_'20151105'_'20151105'
What am I missing here? Thanks in advance!
The problem is that the underscore is a valid character for a variable name. Try one of these:
echo "abc_"$CURRENT_DATE"_"$CURRENT_DATE
echo "abc_${CURRENT_DATE}_$CURRENT_DATE"
Bash doesn't have a concatenation operator, so you concatenate strings by smashing them together in the command; this is what the first example is doing. The second uses braces to explicitly point out the variable name.
You must surround the variable name with ${} in order to isolate it from other valid characters. Like this:
echo "abc_${CURRENT_DATE}_${CURRENT_DATE}"

Unbound variable during url printing in bash/shell

I have 2 variables that I want to use to derive a 3rd variable:
export REGION_NAME=phx
export phx_url=https://www.google.com
I am trying to do the following:
echo "$((${REGION_NAME}_url))"
And I get the following error:
-sh: https://www.google.com: syntax error in expression (error token is "://www.google.com")
All I am trying to do is to derive an environment variable from an other one but it does not work simple like that. I think it has to be escaped and could not find anything online.
Thanks in advance for the help.
$((...)) is arithmetic expansion. You didn't mean that. Try normal variable expansion (with indirection) instead.
REGION_NAME=phx
phx_url=https://www.google.com
R_VAR=${REGION_NAME}_url
echo "${!R_VAR}"
One possible solution is using eval like:
var="phx"
eval "${var}_url='some'"
echo $phx_url #prints "some"
But, I not recommending this (because the eval could be pretty dangerous).
Instead of use associative arrays (aka hash variable), like:
declare -A urls
var="phx"
urls[$var]="some2"
echo "${urls[phx]}" #prints "some2"

BASH variable values as new defined variables

I don't know exactly how to ask this in English, but I want to have the value of a variable as a new variable...
The script also has a loop with increasing numbers, and in the end I want to have the variables VAR1, VAR2 etc.
I'm trying this:
COUNT=$(echo 1)
DEFINE=$(echo VAR$COUNT)
$DEFINE=$(echo gotcha!)
When I try this way, I have this error message:
~/script.sh: line n: VAR1=gotcha!: command not found
I played a bit around with brackets and quotation marks, but it didn't work... any solutions?
The problem is that bash expects a command as a result of expansions, not an assignment. VAR1=gotcha! is not a command, hence the error.
It would be better to use an array:
COUNT=$(echo 1)
VAR[COUNT]='gotcha!'
echo ${VAR[COUNT]}
I guess $(echo 1) stands for a more complex command, otherwise you can just use COUNT=1.
You can use declare to create such a "dynamic" variable, but using an array is probably a better choice.
COUNT=1
DEFINE="VAR$COUNT"
declare "$DEFINE=gotcha"

Resources