Bash 变量替换和字符串
Bash variable substitution and strings
假设我有两个变量:
a="AAA"
b="BBB"
我从文件中读取了一个字符串。该字符串如下:
str='$a $b'
如何从替换变量的第一个字符串创建新字符串?
newstr="AAA BBB"
最简单的解决方案是使用 eval
:
eval echo "$str"
要将其分配给变量,请使用命令替换:
replaced=$(eval echo "$str")
bash 变量 间接 无 eval
:
好吧,因为 eval
是 邪恶的 ,我们可以尝试在没有它们的情况下通过在变量中使用 indirection名字。
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
再试一次:
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
附录 正如@EtanReisner 的评论所正确指出的那样,如果您的字符串确实包含一些 *
或其他 glob 消耗性字符串,你可能不得不使用 set -f
来防止坏事:
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
注意: 我在 newstr+=("$cnt");
处添加了 "
以防止 glob 扩展,但 set -f
似乎是必需的...
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 * *
注2:这离完美的解决方案还有很长的路要走。例如,如果字符串确实包含标点符号,这将不再有效...示例:
str='$var1, this string contain a $var2 as $var3: *'
使用与之前相同的变量 运行 将呈现:
' this string contain a star as *'
因为 ${!var1,}
和 ${!var3:}
不存在。
... 如果 $str
确实包含特殊字符:
正如 @godblessfq 所问:
If str contains a line break, how do I do the substitution and preserve the newline in the output?
所以这不是稳健,因为每个间接变量必须是第一个、最后一个或 space 与所有特殊字符分开!
str=$'$var1 world!\n... 2nd line...'
var1=Hello
newstr=()
set -f
IFS=' ' read -d$'7' -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'}"
免责声明:我 perl
一小时前才发现。但这似乎可以很好地工作,无论您输入什么特殊字符:
newstr=$(a2="$a" b2="$b" perl -pe 's/$a\b/$ENV{a2}/g; s/$b\b/$ENV{b2}/g' <(echo -e "$str"))
测试:
a='A*A\nA'
b='B*B\nB'
str='$a $aa * \n $b $bb'
newstr=$(a2="$a" b2="$b" perl -pe 's/$a\b/$ENV{a2}/g; s/$b\b/$ENV{b2}/g' <(echo -e "$str"))
echo -e "$newstr"
输出:
A*A
A $aa *
B*B
B $bb
假设我有两个变量:
a="AAA"
b="BBB"
我从文件中读取了一个字符串。该字符串如下:
str='$a $b'
如何从替换变量的第一个字符串创建新字符串?
newstr="AAA BBB"
最简单的解决方案是使用 eval
:
eval echo "$str"
要将其分配给变量,请使用命令替换:
replaced=$(eval echo "$str")
bash 变量 间接 无 eval
:
好吧,因为 eval
是 邪恶的 ,我们可以尝试在没有它们的情况下通过在变量中使用 indirection名字。
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
再试一次:
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
附录 正如@EtanReisner 的评论所正确指出的那样,如果您的字符串确实包含一些 *
或其他 glob 消耗性字符串,你可能不得不使用 set -f
来防止坏事:
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
注意: 我在 newstr+=("$cnt");
处添加了 "
以防止 glob 扩展,但 set -f
似乎是必需的...
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 * *
注2:这离完美的解决方案还有很长的路要走。例如,如果字符串确实包含标点符号,这将不再有效...示例:
str='$var1, this string contain a $var2 as $var3: *'
使用与之前相同的变量 运行 将呈现:
' this string contain a star as *'
因为 ${!var1,}
和 ${!var3:}
不存在。
... 如果 $str
确实包含特殊字符:
正如 @godblessfq 所问:
If str contains a line break, how do I do the substitution and preserve the newline in the output?
所以这不是稳健,因为每个间接变量必须是第一个、最后一个或 space 与所有特殊字符分开!
str=$'$var1 world!\n... 2nd line...'
var1=Hello
newstr=()
set -f
IFS=' ' read -d$'7' -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'}"
免责声明:我 perl
一小时前才发现。但这似乎可以很好地工作,无论您输入什么特殊字符:
newstr=$(a2="$a" b2="$b" perl -pe 's/$a\b/$ENV{a2}/g; s/$b\b/$ENV{b2}/g' <(echo -e "$str"))
测试:
a='A*A\nA'
b='B*B\nB'
str='$a $aa * \n $b $bb'
newstr=$(a2="$a" b2="$b" perl -pe 's/$a\b/$ENV{a2}/g; s/$b\b/$ENV{b2}/g' <(echo -e "$str"))
echo -e "$newstr"
输出:
A*A
A $aa *
B*B
B $bb