70

我正在尝试设置PS1提示变量以动态选择颜色。为此,我定义了一堆带有颜色名称的局部变量:

$ echo $Green
\033[0;32m

但我希望在动态分配变量时使用它们,但我不知道如何正确扩展它们:

> colorstr="\${$color}"
> echo $colorstr
${Green}

我已经尝试了十几种, 和双引号的组合,但似乎都不起作用evalecho扩展变量的逻辑方式(我认为)会导致错误:

> colorstr="${$color}"
-bash: ${$color}: bad substitution

(为了清楚起见,我使用>而不是$提示字符,但我使用的是 bash)

如何扩展该变量?即,以某种方式获得“绿色”这个词的价值\033[0;32m?并且最好让 bash 或终端也将其解析\033[0;32m为绿色。

编辑:我以前误用过${!x}eval echo $x所以我接受了这些作为解决方案。对于(也许是病态的)好奇,函数和PS1变量都在这个要点上:https ://gist.github.com/4383597

4

5 回答 5

79

Usingeval是经典的解决方案,但bash有一个更好的(更容易控制,更少笨拙的)解决方案:

  • ${!colour}

Bash(4.1)参考手册说:

如果参数的第一个字符是感叹号(!),则引入了变量间接级别。Bash 使用由其余参数形成的变量的值作为变量的名称;然后扩展此变量,并将该值用于替换的其余部分,而不是参数本身的值。这称为间接扩展

例如:

$ Green=$'\033[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:
$

(该odx命令非常不标准,但只是以十六进制格式转储其数据,右侧显示可打印的字符。由于纯echo文本没有显示任何内容,我需要查看正在回显的内容,因此我使用了我写的一位老朋友大约 24 年前。)

于 2012-12-27T06:09:16.697 回答
20

使用 eval 应该这样做:

green="\033[0;32m"
colorstr="green"
eval echo -e "\$$colorstr" test           # -e = enable backslash escapes
test

最后一个测试是绿色的。

于 2012-12-27T03:55:23.400 回答
1

Bash 支持关联数组。当你可以使用字典时不要使用间接。如果您没有关联数组,请升级到 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 "$2"'[${clrs[x]}]=$(tput "${1#--}" "$x")'
                done
                ;;
            misc)
                for x in "${msc[@]}"; do
                    eval "$2"'[$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[$1]:+_}} ]]; then
            printf '%s%s%s\n' "${fgColors[${1}]}" "this text is ${1}" "${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 "$@"

尽管我们使用的是eval,但出于不同的原因,它是一种不同类型的间接。请注意所有必要的保证是如何确保安全的。

另见: http: //mywiki.wooledge.org/BashFAQ/006

于 2012-12-29T01:16:41.247 回答
0

您将需要为函数编写别名。查看http://tldp.org/LDP/abs/html/functions.html,不错的小教程和一些示例。

编辑:对不起,看起来我误解了这个问题。首先,您似乎使用了错误的变量,请查看http://www.thegeekstuff.com/2010/07/bash-string-manipulation/。另外,什么在调用这个脚本?您是将其添加到 .bash_profile 还是您的用户可以启动的脚本?使用导出应该使更改立即生效而无需重新登录。

var Green="\[\e[32m\]"
var Red="\[\e41m\]"

export PS1="${Green} welcome ${Red} user>"
于 2012-12-27T03:47:15.340 回答
0

您的第一个结果显示了问题:

$ echo $Green
\033[0;32m

变量 Green 包含一个字符串a backlash, a zero, a 3, etc.

它是由:Green="\033[0;32m". 因此,它不是颜色代码。
需要解释变量内的文本(使用 echo -e、printf 或 $'...')。

让我用代码解释一下:

$ Green="\033[0;32m"    ;     echo "  $Green   test   "
  \033[0;32m   test     

你的意思是:

$  Green="$(echo -e "\033[0;32m" )"    ;     echo "  $Green   test   "
 test   

在伟大的颜色绿色。这可以打印颜色,但对 PS1 没有用:

$  Green="\033[0;32m"    ;     echo -e "  $Green   test   "
 test   

因为这意味着必须在字符串echo -e起作用之前对其进行解释。

一种更简单的方法(在 bash 中)是:

$ Green=$'\033[0;32m'    ;     echo "  $Green   test   "
  test   

请注意` $'...' `

解决了变量的问题后Green,通过 var colorstr 的值间接访问它是第二个问题,可以通过以下方式解决:

$ eval echo \$$colorstr testing colors
testing colors
$ echo ${!colorstr} testing colors
testing colors

注意请不要使用未引用的值(就像我在这里所做的那样,因为这些值在我的控制之下)。学习正确引用,例如:

$ eval echo \"\$$colorstr testing colors\"

有了这个,你可以写一个相当于:

export PS1="${Green} welcome ${Red} user>"

和:

Green=$'\033[0;32m'    Red=$'\033[0;31m'
color1=Green           color2=Red
export PS1="${!color1} welcome ${!color2} user>"
于 2015-12-17T06:51:16.853 回答