3

I have a file contains a few lines, and in some lines there is a variable like this:

The-first-line
The-second-${VARIABLE}-line
The-third-line

In a bash scrip, I want to read the lines and resolve the variable wherever exists.

VARIABLE=Awesome
LINES=$(echo $(cat file.txt))
for i in $LINES
do :
  echo "$i"
done

The output is same as the input file (unresolved variables) but I want something like this:

The-first-line
The-second-Awesome-line
The-third-line

Thanks in advance for any help!

Jalal Sajadi
  • 412
  • 6
  • 12

3 Answers3

4

You can try the following (with a recent enough version of bash that supports namerefs):

while IFS= read -r line; do
  while [[ "$line" =~ (.*)\$\{([^}]+)\}(.*) ]]; do
    declare -n var="${BASH_REMATCH[2]}"
    printf -v line '%s%s%s' "${BASH_REMATCH[1]}" "$var" "${BASH_REMATCH[3]}"
  done
  printf '%s\n' "$line"
done < file.txt

In the innermost loop we iterate as long as there is a ${VARIABLE} variable reference, that we replace by the variable's value, thanks to BASH_REMATCH, the var nameref and the -v option of printf.

Warning: if you have a variable named, e.g., VARIABLE and which value is literally ${VARIABLE}, this script will enter an infinite loop.

Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
2

If you export your variable you may find envsubst does what you want (eg, How to substitute shell variables in complex text files).

For this particular case:

$ export VARIABLE='Awesome'  # or: VARIABLE='Awesome'; export VARIABLE
$ envsubst < file.txt
The-first-line
The-second-Awesome-line
The-third-line
markp-fuso
  • 28,790
  • 4
  • 16
  • 36
  • Thanks! The problem is that I'm using a docker container based on `openjdk:11-jre-slim` which doesn't contain `envsubst` by default and I can't add that package (for some reasons). – Jalal Sajadi Aug 23 '22 at 14:11
  • 1
    @JalalSajadi according to this [Q&A](https://unix.stackexchange.com/a/635802) there's a docker-related command `envplate`; (NOTE: I have no idea if this is part of a docker default installation nor do I have any experience with this comment ... I'm just passing on what I found with some webs searching) – markp-fuso Aug 23 '22 at 14:49
1

A quick way to do this would be using the sed command to replace ${variable} in the line with $VARIABLE. Make sure to escape the $ in ${VARIABLE} so it doesn't think it's an actual variable. And to use double quotes so it references the variable in $VARIABLE.

VARIABLE=Awesome
LINES=$(echo $(cat var_file))
for i in $LINES
do :
  echo $i | sed "s/\${VARIABLE}/$VARIABLE/"
done

Let me know if this works for you or if you have any questions.

jbert
  • 162
  • 3
  • Thanks jbert! The variables could be anything, not only `VARIABLE`. But I think I can use some regex for catching all other variables. – Jalal Sajadi Aug 23 '22 at 14:15
  • 1
    This won't work in the case of `VARIABLE='Awesome&Amazing'`, for instance. Aside from this, there are many problems with this code: Using a `for` loop to read a file is one of them ([DontReadLinesWithFor](https://mywiki.wooledge.org/DontReadLinesWithFor)). – M. Nejat Aydin Aug 23 '22 at 16:21