Bash expande variable en una variable

Estoy intentando configurar mi variable de solicitud de PS1 para elegir dinámicamente un color. Para hacer esto, he definido un grupo de variables locales con nombres de colores:

 $ echo $Green \033[0;32m 

pero esperaba usarlos en la asignación dinámica de variables, pero no puedo encontrar la manera de expandirlos correctamente:

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

Probé una docena de combinaciones de eval , echo y comillas dobles, y ninguna parece funcionar. La forma lógica (pensé) de expandir los resultados de la variable en un error:

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

(para mayor claridad, he usado > lugar de $ para el carácter de solicitud, pero estoy usando bash)

¿Cómo puedo expandir esa variable? es decir, de alguna manera obtener la palabra “Verde” en el valor \033[0;32m ? Y, preferiblemente, tenga bash o el análisis de terminal que \033[0;32m como el color verde también.

EDITAR: Estaba mal-usando ${!x} y eval echo $x previamente, así que los he aceptado como soluciones. Para el (quizás morbosamente) curioso, las funciones y la variable PS1 están en esta esencia: https://gist.github.com/4383597

El uso de eval es la solución clásica, pero bash tiene una mejor solución (más fácil de controlar, menos similar al blunderbuss):

  • ${!colour}

El manual de referencia de Bash (4.1) dice:

Si el primer carácter de parámetro es un signo de exclamación (!), Se introduce un nivel de indirección variable. Bash usa el valor de la variable formada a partir del rest del parámetro como el nombre de la variable; esta variable luego se expande y ese valor se usa en el rest de la sustitución, en lugar del valor del parámetro en sí mismo. Esto se conoce como expansión indirecta .

Por ejemplo:

 $ 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: $ 

(El comando odx es muy no estándar, pero simplemente vuelca sus datos en un formato hexadecimal con caracteres imprimibles que se muestran a la derecha. Como el echo no mostró nada y necesitaba ver lo que se repetía, utilicé un viejo amigo Escribí hace unos 24 años.)

Usar eval debería hacerlo:

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

La última prueba es de color verde.

Bash admite matrices asociativas. No use la indirección cuando podría usar un dict. Si no tiene matrices asociativas, actualice a bash 4, ksh93 o zsh. Aparentemente, mksh también los está agregando, así que debería haber muchas opciones.

 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 "$@" 

Aunque estamos usando eval , es un tipo diferente de indirección por una razón diferente. Tenga en cuenta cómo se hacen todas las garantías necesarias para hacer que esto sea seguro.

Ver también: http://mywiki.wooledge.org/BashFAQ/006

Querrá escribir un alias para una función. Consulte http://tldp.org/LDP/abs/html/functions.html , pequeño tutorial decente y algunos ejemplos.

EDITAR: Lo siento, parece que he entendido mal el problema. Primero parece que estás usando las variables incorrectamente, revisa http://www.thegeekstuff.com/2010/07/bash-string-manipulation/ . Además, ¿qué está invocando este script? ¿Está agregando esto al .bash_profile o es este un script que sus usuarios pueden iniciar? El uso de la exportación debe hacer que los cambios entren en vigencia de inmediato sin necesidad de relog.

 var Green="\[\e[32m\]" var Red="\[\e41m\]" export PS1="${Green} welcome ${Red} user>" 

Su primer resultado muestra el problema:

 $ echo $Green \033[0;32m 

La variable Verde contiene una cadena de a backlash, a zero, a 3, etc.

Fue establecido por: Green="\033[0;32m" . Como tal, no es un código de color.
El texto dentro de la variable necesita ser interpretado (usando echo -e, printf o $ ‘…’).

Déjame explicarte con el código:

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

Lo que quieres hacer es:

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

En gran color verde. Esto podría imprimir el color, pero no será útil para PS1:

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

Como significa que la cuerda debe ser interpretada por echo -e antes de que funcione.

Una manera más fácil (en bash) es:

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

Tenga en cuenta que ` $'...' `

Habiendo resuelto el problema de la variable Green , accediendo indirectamente por el valor de var colorstr es un segundo problema que podría ser resuelto por:

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

Nota: Por favor, no trabaje con valores no citados (como lo hice aquí porque los valores estaban bajo mi control) en general. Aprende a citar correctamente, como:

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

Y con eso, podrías escribir una PS1 equivalente a:

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

con:

 Green=$'\033[0;32m' Red=$'\033[0;31m' color1=Green color2=Red export PS1="${!color1} welcome ${!color2} user>"