Bash变量替换和字符串 [英] Bash variable substitution and strings
问题描述
假设我有两个变量:
a ="AAA"b ="BBB"
我从文件中读取了一个字符串.该字符串如下:
str ='$ a $ b'
如何从第一个替换变量的字符串创建新字符串?
newstr ="AAA BBB"
另一种尝试:
var1 ="Hello"var2 ="2015"str ='$ var1世界!新年快乐$ var2'newstr =()为$ nt中的cnt;做["$ {cnt:0:1}" =='$']&&cnt = $ {cnt:1}&&cnt = $ {!cnt}newstr + =($ cnt)完毕newstr ="$ {newstr [*]}"回声$ newstr你好,世界!2015年新年快乐
附录正如@EtanReisner的评论所正确指出的那样,如果您的字符串中确实包含某些 *
或其他 glob 消耗性st绳,您可能必须使用 set -f
防止不良行为:
cd/binvar1 ="Hello"var2 ="star"var3 ="*"str ='$ var1这个字符串包含一个$ var2作为$ var3 *'newstr =()为$ nt中的cnt;做["$ {cnt:0:1}" =='$']&&cnt = $ {cnt:1}&&cnt = $ {!cnt};newstr + =("$ cnt");完毕;newstr ="$ {newstr [*]}"回声"$ newstr"您好,此字符串包含一个星号,如* bash bunzip2 busybox .... zmore znew回声$ {#newstr}1239
注意:我在 newstr + =("$ cnt");
处添加了"
,以防止全局扩展,但是设置-f
似乎是必需的...
newstr =()设置-f为$ nt中的cnt;做["$ {cnt:0:1}" =='$']&&cnt = $ {cnt:1}&&cnt = $ {!cnt}newstr + =("$ cnt")完毕设置+ fnewstr ="$ {newstr [*]}"回声"$ newstr"您好,此字符串包含一个星号* *
注意2:这离完美的解决方案还差得很远.对于示例,如果字符串确实包含振动,则该操作将不再起作用...示例:
str ='$ var1,此字符串包含一个$ var2作为$ var3:*'
具有与先前运行相同的变量的变量将呈现:'此字符串包含一个星号*'
,因为 $ {!var1,}
和 $ {!var3:}
不存在./p>
...并且如果 $ str
确实包含特殊字符:
@godblessfq 询问:
如果str包含换行符,该如何替换并在输出中保留换行符?
因此,这不是健壮,因为每个间接变量必须必须与所有特殊字符分隔成第一个,最后一个或空格!
str = $'$ var1 world!\ n ...第二行...'var1 =你好newstr =()设置-fIFS =''读取-d $'\ 377'-ra数组<<<"$ str"对于"$ {array [@]}"中的cnt;执行["$ {cnt:0:1}" =='$']&&cnt = $ {cnt:1}&&cnt = $ {!cnt}newstr + =("$ cnt")完毕设置+ fnewstr ="$ {newstr [*]}"回声"$ newstr"你好,世界!第二行
由于<<<
内联字符串添加尾随换行符,因此可以编写最后一个 echo
命令:
echo"$ {newstr%$'\ n'}"
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"
解决方案 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'}"
这篇关于Bash变量替换和字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
var1 ="Hello"var2 ="2015"str ='$ var1世界!新年快乐$ var2'newstr =()为$ nt中的cnt;做["$ {cnt:0:1}" =='$']&&cnt = $ {cnt:1}&&cnt = $ {!cnt}newstr + =($ cnt)完毕newstr ="$ {newstr [*]}"回声$ newstr你好,世界!2015年新年快乐
*
或其他 glob 消耗性st绳,您可能必须使用 set -f
防止不良行为: cd/binvar1 ="Hello"var2 ="star"var3 ="*"str ='$ var1这个字符串包含一个$ var2作为$ var3 *'newstr =()为$ nt中的cnt;做["$ {cnt:0:1}" =='$']&&cnt = $ {cnt:1}&&cnt = $ {!cnt};newstr + =("$ cnt");完毕;newstr ="$ {newstr [*]}"回声"$ newstr"您好,此字符串包含一个星号,如* bash bunzip2 busybox .... zmore znew回声$ {#newstr}1239
newstr + =("$ cnt");
处添加了"
,以防止全局扩展,但是设置-f
似乎是必需的... newstr =()设置-f为$ nt中的cnt;做["$ {cnt:0:1}" =='$']&&cnt = $ {cnt:1}&&cnt = $ {!cnt}newstr + =("$ cnt")完毕设置+ fnewstr ="$ {newstr [*]}"回声"$ newstr"您好,此字符串包含一个星号* *
str ='$ var1,此字符串包含一个$ var2作为$ var3:*'
'此字符串包含一个星号*'
,因为 $ {!var1,}
和 $ {!var3:}
不存在./p> $ str
确实包含特殊字符:如果str包含换行符,该如何替换并在输出中保留换行符?
str = $'$ var1 world!\ n ...第二行...'var1 =你好newstr =()设置-fIFS =''读取-d $'\ 377'-ra数组<<<"$ str"对于"$ {array [@]}"中的cnt;执行["$ {cnt:0:1}" =='$']&&cnt = $ {cnt:1}&&cnt = $ {!cnt}newstr + =("$ cnt")完毕设置+ fnewstr ="$ {newstr [*]}"回声"$ newstr"你好,世界!第二行
<<<
内联字符串添加尾随换行符,因此可以编写最后一个 echo
命令: echo"$ {newstr%$'\ n'}"
a="AAA"
b="BBB"
str='$a $b'
newstr="AAA BBB"
eval
: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
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
*
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
"
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 * *
str='$var1, this string contain a $var2 as $var3: *'
' this string contain a star as *'
because ${!var1,}
and ${!var3:}
don't exist.$str
do contain special chars:If str contains a line break, how do I do the substitution and preserve the newline in the output?
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...
<<<
inline string add a trailing newline, last echo
command could be written:echo "${newstr%$'\n'}"