5

I'm new to bash scripting and have a question about using properties from a .properties file within a bash script.

I have seen a bash properties file that uses'.' between variable names, for example:

this.prop.one=someProperty

and I've seen them called from within a script like:

echo ${this.prop.one}

But when I try to set this property I get an error:

./test.sh: line 5: ${this.prop.one}: bad substitution

I can use properties if I do it without '.' in the variable names, and include the props file:

#!/bin/bash
. test.properties
echo ${this_prop_one}

I would really like to be able to use '.' in the variable names, and, if at all possible, not have to include . test.properties in the script.

Is this possible?

UPDATE:

Thanks for your answers! Well, then this is strange. I'm working with a bash script that looks like this (a service for glassfish):

#!/bin/bash

start() {
        sudo ${glassfish.home.dir}/bin/asadmin start-domain domain1
}

...

...and there are property files like this (build.properties):

# glassfish
glassfish.version=2.1
glassfish.home.dir=${app.install.dir}/${glassfish.target}
...

So, there must be some way of doing this right? Are these maybe not considered 'variables' by definition if they're declared in a properties file? Thanks again.

Matt
  • 5,408
  • 14
  • 52
  • 79
  • possible duplicate of [Allowed characters in linux environment variable names](http://stackoverflow.com/questions/2821043/allowed-characters-in-linux-environment-variable-names) – Digital Trauma Feb 06 '14 at 00:32
  • @DigitalTrauma ...this is duplicate if it's read only as referring to _environment variables_. If the goal is just to be able to use such variables (which is how I read the question), there are other ways to store them which *will* work. – Charles Duffy Feb 06 '14 at 01:03
  • @CharlesDuffy - yes, thats a great way around this problem - close-vote retracted. – Digital Trauma Feb 06 '14 at 01:06
  • @MattB, no, your existing script using `${glassfish.home.dir}` is not and has never been valid bash. I'd hazard it's something else -- like a template run through a Java program to create a bash script. – Charles Duffy Feb 07 '14 at 15:08
  • @MattB ...by the way, I've tried googling for the code you gave, and the only place I find `sudo ${glassfish.home.dir}/bin/asadmin` is this question itself. A pointer to where you found it, to allow for analysis of context, would be helpful. – Charles Duffy Feb 07 '14 at 17:54
  • I'm also curious as to whether, perhaps, the place you're looking at is a template used to _generate_ a bash script rather than something directly run by bash. That's definitely true for the .properties files -- those are evaluated by Java library code, not by bash itself. – Charles Duffy Jun 30 '15 at 15:13
  • @Matt, btw, this may well be too late, but I've amended my answer to cover recursive lookups (for the case where your properties refer to other properties in turn). – Charles Duffy Nov 29 '16 at 16:19

3 Answers3

10

Load them into an associative array. This will require your shell to be bash 4.x, not /bin/sh (which, even when a symlink to bash, runs in POSIX compatibility mode).

declare -A props
while read -r; do
  [[ $REPLY = *=* ]] || continue
  props[${REPLY%%=*}]=${REPLY#*=}
done <input-file.properties

...after which you can access them like so:

echo "${props[this.prop.name]}"

If you want to recursively look up references, then it gets a bit more interesting.

getProp__property_re='[$][{]([[:alnum:].]+)[}]'
getProp() {
  declare -A seen=( ) # to prevent endless recursion
  declare propName=$1
  declare value=${props[$propName]}
  while [[ $value =~ $getProp__property_re ]]; do
    nestedProp=${BASH_REMATCH[1]}
    if [[ ${seen[$nestedProp]} ]]; then
      echo "ERROR: Recursive definition encountered looking up $propName" >&2
      return 1
    fi
    value=${value//${BASH_REMATCH[0]}/${props[$nestedProp]}}
  done
  printf '%s\n' "$value"
}

If we have props defined as follows (which you could also get by running the loop at the top of this answer with an appropriate input-file.properties):

declare -A props=(
  [glassfish.home.dir]='${app.install.dir}/${glassfish.target}'
  [app.install.dir]=/install
  [glassfish.target]=target
)

...then behavior is as follows:

bash4-4.4$ getProp glassfish.home.dir
/install/target
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • fantastic answer! It solved exactly my problem. The hint to use the explicit way to address the bash interpreter was a vital part of the solution! Thank you! – LastZolex Nov 08 '21 at 10:53
4

No can do. The bash manual says this about variable names:

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.

Dots not allowed.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • You could `cat` the file, pass it through `sed` (replacing the . by _) adn `eval` the result - if you trust its content. – Johannes H. Feb 06 '14 at 00:40
  • something similar to `eval $( cat file.properties | sed y/./_/ )` - just make sure that the eval is not executed in a subshell (so not piping anything into it for example) – Johannes H. Feb 06 '14 at 00:43
  • @JohannesH., that's rather scary from a security perspective; properties files are expected to contain data, but by eval'ing them, you're treating them as code. – Charles Duffy Feb 06 '14 at 01:02
  • @CharlesDuffy I know. This is a very quick and dirty solution, that only work if they're properly formatted (that means, no spaces before and after the =, values surrounded by `"`) and, as stated in my suggestion, you trust everything in them. This is, of course, **no general purpose solution** at all. – Johannes H. Feb 06 '14 at 01:03
  • 1
    True, but the OP wanted to avoid that, too ;) – Johannes H. Feb 06 '14 at 01:06
1

dot is not allowed to be variable name. so you cannot just simply source the property file.

What you can do is:

"parse" the file, not source it. E.g. with perl, awk or grep to get the value of interesting property name, and assign it to your shell var.

if you do want to set a var with dot in its name, you can use env 'a.b.c=xyz' and get the a.b.c from env output.

Kent
  • 189,393
  • 32
  • 233
  • 301
  • That's not supported under all shells -- some versions of bash will actually delete any environment variables which aren't valid shell variables. – Charles Duffy Feb 06 '14 at 00:58