Bash 在变量中扩展变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14049057/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash expand variable in a variable
提问by keflavich
I'm trying to set up my PS1
prompt variable to dynamically choose a color. To do this, I've defined a bunch of local variables with color names:
我正在尝试设置我的PS1
提示变量以动态选择颜色。为此,我定义了一堆带有颜色名称的局部变量:
$ echo $Green
3[0;32m
but I was hoping to use those in dynamically assigning variables, but I can't figure out how to expand them properly:
但我希望在动态分配变量中使用它们,但我不知道如何正确扩展它们:
> colorstr="${$color}"
> echo $colorstr
${Green}
I've tried a dozen combinations of eval
, echo
, and double-quotes, and none seem to work. The logical way (I thought) to expand the variable results in an error:
我试过一打组合eval
,echo
双引号,并且,没有似乎工作。扩展变量的逻辑方式(我认为)会导致错误:
> colorstr="${$color}"
-bash: ${$color}: bad substitution
(for clarity I've used >
instead of $
for the prompt character, but I am using bash)
(为了清楚起见,我使用了>
而不是$
提示字符,但我使用的是 bash)
How can I expand that variable? i.e., somehow get the word "Green" to the value \033[0;32m
? And prefereably, have bash or the terminal parse that \033[0;32m
as the color green too.
如何扩展该变量?即,以某种方式将“绿色”一词赋予值\033[0;32m
?最好让 bash 或终端将其解析\033[0;32m
为绿色。
EDIT: I was mis-using ${!x}
and eval echo $x
previously, so I've accepted those as solutions. For the (perhaps morbidly) curious, the functions and PS1
variable are on this gist: https://gist.github.com/4383597
编辑:我是误用${!x}
和eval echo $x
以前的,所以我接受了这些作为解决方案。对于(可能是病态的)好奇,函数和PS1
变量在这个要点上:https: //gist.github.com/4383597
回答by Jonathan Leffler
Using eval
is the classic solution, but bash
has a better (more easily controlled, less blunderbuss-like) solution:
Usingeval
是经典的解决方案,但bash
有一个更好的(更容易控制,更少像大炮一样)的解决方案:
${!colour}
${!colour}
The Bash (4.1) reference manualsays:
Bash (4.1)参考手册说:
If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion.
如果参数的第一个字符是感叹号 (!),则引入了一个变量间接级别。Bash 使用由参数的其余部分形成的变量的值作为变量的名称;这个变量然后被扩展,并且该值用于替换的其余部分,而不是参数本身的值。这称为间接扩展。
For example:
例如:
$ Green=$'3[32;m'
$ echo "$Green" | odx
0x0000: 1B 5B 33 32 3B 6D 0A .[32;m.
0x0007:
$ colour=Green
$ echo $colour
Green
$ echo ${!colour} | odx
0x0000: 1B 5B 33 32 3B 6D 0A .[32;m.
0x0007:
$
(The odx
command is very non-standard but simply dumps its data in a hex format with printable characters shown on the right. Since the plain echo
didn't show anything and I needed to see what was being echoed, I used an old friend I wrote about 24 years ago.)
(该odx
命令非常不标准,但只是以十六进制格式转储其数据,右侧显示可打印字符。由于平原echo
没有显示任何内容,我需要查看正在回显的内容,我使用了我写的一个老朋友大约 24 年前。)
回答by perreal
Using eval should do it:
使用 eval 应该这样做:
green="3[0;32m"
colorstr="green"
eval echo -e "$$colorstr" test # -e = enable backslash escapes
test
The last test is in color green.
最后一个测试是绿色。
回答by ormaaj
Bash supports associative arrays. Don't use indirection when you could use a dict. If you don't have associative arrays, upgrade to bash 4, ksh93, or zsh. Apparently mksh is adding them eventually as well, so there should be plenty of choice.
Bash 支持关联数组。可以使用 dict 时不要使用间接。如果您没有关联数组,请升级到 bash 4、ksh93 或 zsh。显然 mksh 最终也会添加它们,所以应该有很多选择。
function colorSet {
typeset -a \
clrs=(black red green orange blue magenta cyan grey darkgrey ltred ltgreen yellow ltblue ltmagenta ltcyan white) \
msc=(sgr0 bold dim smul blink rev invis)
typeset x
while ! ${2:+false}; do
case ${1#--} in
setaf|setab)
for x in "${!clrs[@]}"; do
eval ""'[${clrs[x]}]=$(tput "${1#--}" "$x")'
done
;;
misc)
for x in "${msc[@]}"; do
eval ""'[$x]=$(tput "$x")'
done
;;
*)
return 1
esac
shift 2
done
}
function main {
typeset -A fgColors bgColors miscEscapes
if colorSet --setaf fgColors --setab bgColors --misc miscEscapes; then
if [[ -n ${1:+${fgColors[]:+_}} ]]; then
printf '%s%s%s\n' "${fgColors[]}" "this text is " "${miscEscapes[sgr0]}"
else
printf '%s, %s\n' "${1:-Empty}" 'no such color.' >&2
return 1
fi
else
echo 'Failed setting color arrays.' >&2
return 1
fi
}
main "$@"
Though we're using eval
, it's a different type of indirection for a different reason. Note how all the necessary guarantees are made for making this safe.
尽管我们正在使用eval
,但由于不同的原因,它是一种不同类型的间接。注意所有必要的保证是如何确保安全的。
See also: http://mywiki.wooledge.org/BashFAQ/006
回答by ormaaj
Your first result shows the problem:
您的第一个结果显示了问题:
$ echo $Green 3[0;32m
$ echo $Green 3[0;32m
The variable Green contains an string of a backlash, a zero, a 3, etc.
.
变量 Green 包含一个字符串a backlash, a zero, a 3, etc.
。
It was set by: Green="\033[0;32m"
. As such it is not a color code.
The text inside the variable needs to be interpreted (using echo -e, printf or $'...').
它是由: 设置的Green="\033[0;32m"
。因此,它不是颜色代码。
需要解释变量内的文本(使用 echo -e、printf 或 $'...')。
Let me explain with code:
我用代码解释一下:
$ Green="3[0;32m" ; echo " $Green test "
3[0;32m test
What you mean to do is:
你的意思是:
$ Green="$(echo -e "3[0;32m" )" ; echo " $Green test "
test
In great color green. This could print the color but will not be useful for PS1:
在伟大的颜色绿色。这可以打印颜色,但对 PS1 没有用:
$ Green="3[0;32m" ; echo -e " $Green test "
test
As it means that the string has to be interpreted by echo -e
before it works.
因为这意味着字符串必须echo -e
在它工作之前被解释。
An easier way (in bash) is :
一种更简单的方法(在 bash 中)是:
$ Green=$'3[0;32m' ; echo " $Green test "
test
Please note the ` $'...' `
请注意 ` $'...' `
Having solved the issue of the variable Green
, accesing it indirectly by the value of var colorstr is a second problem that could be solved by either:
解决了变量的问题后Green
,通过 var colorstr 的值间接访问它是第二个问题,可以通过以下任一方法解决:
$ eval echo $$colorstr testing colors
testing colors
$ echo ${!colorstr} testing colors
testing colors
NotePlease do not work with un-quoted values (as I did here because the values were under my control) in general. Learn to quote correctly, like:
注意请不要使用未引用的值(就像我在这里所做的那样,因为这些值在我的控制之下)。学习正确引用,例如:
$ eval echo \"$$colorstr testing colors\"
And with that, you could write an PS1 equivalent to:
有了这个,您可以编写一个等效于以下内容的 PS1:
export PS1="${Green} welcome ${Red} user>"
with:
和:
Green=$'3[0;32m' Red=$'3[0;31m'
color1=Green color2=Red
export PS1="${!color1} welcome ${!color2} user>"
回答by ormaaj
You will want to write an alias to a function. Check out http://tldp.org/LDP/abs/html/functions.html, decent little tutorial and some examples.
您将需要为函数编写别名。查看http://tldp.org/LDP/abs/html/functions.html,不错的小教程和一些示例。
EDIT: Sorry, looks like I misunderstood the issue. First it looks like your using the variables wrong, check out http://www.thegeekstuff.com/2010/07/bash-string-manipulation/. Also, what is invoking this script? Are you adding this to the .bash_profile or is this a script your users can launch? Using export should make the changes take effect right away without needed relog.
编辑:对不起,看起来我误解了这个问题。首先看起来您使用的变量错误,请查看http://www.thegeekstuff.com/2010/07/bash-string-manipulation/。另外,什么是调用这个脚本?您是将此添加到 .bash_profile 还是您的用户可以启动的脚本?使用 export 应该使更改立即生效,而无需重新登录。
var Green="\[\e[32m\]"
var Red="\[\e41m\]"
export PS1="${Green} welcome ${Red} user>"