Bash variable substitution and strings

丶灬走出姿态 提交于 2019-12-24 03:00:12

问题


Let's say I have two variables:

a="AAA"
b="BBB"

I read a string from a file. This string is the following:

str='$a $b'

How to create a new string from the first one that substitutes the variables?

newstr="AAA BBB"

回答1:


bash variable indirection whithout eval:

Well, as eval is evil, we may try to make this whithout them, by using indirection in variable names.

 a="AAA"
 b="BBB"
 str='$a $b'

 newstr=()
 for cnt in $str ;do
     [ "${cnt:0:1}" == '$' ] && cnt=${cnt:1} && cnt=${!cnt}
     newstr+=($cnt)
   done
 newstr="${newstr[*]}"

 echo $newstr
 AAA BBB

Another try:

var1="Hello"
var2="2015"

str='$var1 world! Happy new year $var2'

newstr=()
for cnt in $str ;do
    [ "${cnt:0:1}" == '$' ] && cnt=${cnt:1} && cnt=${!cnt}
    newstr+=($cnt)
  done
newstr="${newstr[*]}"

echo $newstr 
Hello world! Happy new year 2015

Addendum As correctly pointed by @EtanReisner's comment, if your string do contain some * or other glob expendable stings, you may have to use set -f to prevent bad things:

cd /bin
var1="Hello"
var2="star"
var3="*"
str='$var1 this string contain a $var2 as $var3 *'

newstr=()
for cnt in $str ;do
     [ "${cnt:0:1}" == '$' ] && cnt=${cnt:1} && cnt=${!cnt};
     newstr+=("$cnt");
   done;
newstr="${newstr[*]}"

echo "$newstr"
Hello this string contain a star as * bash bunzip2 busybox....zmore znew

echo ${#newstr}
1239

Note: I've added " at newstr+=("$cnt"); to prevent glob expansion, but set -f seem required...

newstr=()
set -f
for cnt in $str ;do
    [ "${cnt:0:1}" == '$' ] && cnt=${cnt:1} && cnt=${!cnt}
    newstr+=("$cnt")
  done
set +f
newstr="${newstr[*]}"

echo "$newstr"
Hello this string contain a star as * *

Nota 2: This is far away from a perfect solution. For sample if string do contain ponctuation, this won't work again... Example:

str='$var1, this string contain a $var2 as $var3: *'

with same variables as previous run will render: ' this string contain a star as *' because ${!var1,} and ${!var3:} don't exist.

... and if $str do contain special chars:

As @godblessfq asked:

If str contains a line break, how do I do the substitution and preserve the newline in the output?

So this is not robust as every indirected variable must be first, last or space separated from all special chars!

str=$'$var1 world!\n... 2nd line...'
var1=Hello
newstr=()
set -f
IFS=' ' read -d$'\377' -ra array <<<"$str"
for cnt in "${array[@]}";do
    [ "${cnt:0:1}" == '$' ] && cnt=${cnt:1} && cnt=${!cnt}
    newstr+=("$cnt")
  done
set +f
newstr="${newstr[*]}"

echo "$newstr"
Hello world!
... 2nd line...

As <<< inline string add a trailing newline, last echo command could be written:

echo "${newstr%$'\n'}"



回答2:


The easiest solution is to use eval:

eval echo "$str"

To assing it to a variable, use command substitution:

replaced=$(eval echo "$str")


来源:https://stackoverflow.com/questions/27816750/bash-variable-substitution-and-strings

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!