Bash развернуть переменную в переменной
Я пытаюсь настроить приглашающую переменную PS1
для динамического выбора цвета. Для этого я определил кучу локальных переменных с именами цветов:
$ echo $Green
\033[0;32m
но я надеялся использовать их в динамическом назначении переменных, но я не могу понять, как их правильно расширять:
> colorstr="\${$color}"
> echo $colorstr
${Green}
Я пробовал дюжину комбинаций eval
, echo
и двойных кавычек, и ни один из них не работает. Логический способ (я думал) развернуть переменную приводит к ошибке:
> colorstr="${$color}"
-bash: ${$color}: bad substitution
(для ясности я использовал >
вместо $
для символа приглашения, но я использую bash)
Как я могу расширить эту переменную? т.е. каким-то образом получить слово "зеленый" в значение \033[0;32m
? И предпочтительно, bash или терминальный синтаксический анализ, что \033[0;32m
как зеленый цвет тоже.
EDIT: раньше я использовал ${!x}
и eval echo $x
, поэтому я принял их как решения. Для (возможно, болезненно) любопытных функции и переменная PS1
находятся в этом значении: https://gist.github.com/4383597
Ответы
Ответ 1
Использование eval
является классическим решением, но bash
имеет лучшее (более легко управляемое, менее blunderbuss-подобное) решение:
Справочное руководство 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
очень нестандартная, но просто выгружает свои данные в шестнадцатеричном формате с печатными символами, показанными справа. Поскольку plain echo
ничего не показывал, и мне нужно было посмотреть, что было эхом, я использовал старого друга, которого я написал около 24 лет назад.)
Ответ 2
Использование eval должно сделать это:
green="\033[0;32m"
colorstr="green"
eval echo -e "\$$colorstr" test # -e = enable backslash escapes
test
Последний тест имеет зеленый цвет.
Ответ 3
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 "$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 "[email protected]"
Хотя мы используем eval
, это другой тип косвенности по другой причине. Обратите внимание, что все необходимые гарантии сделаны для обеспечения безопасности.
Смотрите также: http://mywiki.wooledge.org/BashFAQ/006
Ответ 4
Вы хотите написать псевдоним функции. Проверьте http://tldp.org/LDP/abs/html/functions.html, достойный небольшой учебник и некоторые примеры.
EDIT: Извините, похоже, я неправильно понял проблему. Сначала похоже, что вы неправильно используете переменные, проверьте http://www.thegeekstuff.com/2010/07/bash-string-manipulation/. Кроме того, что вызывает этот script? Вы добавляете это в .bash_profile или это script, который могут запускать ваши пользователи? Использование экспорта должно привести к тому, что изменения вступят в силу сразу же без необходимости использования relog.
var Green="\[\e[32m\]"
var Red="\[\e41m\]"
export PS1="${Green} welcome ${Red} user>"
Ответ 5
Ваш первый результат показывает проблему:
$ 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\"
И с этим вы можете написать эквивалент PS1:
export PS1="${Green} welcome ${Red} user>"
с:
Green=$'\033[0;32m' Red=$'\033[0;31m'
color1=Green color2=Red
export PS1="${!color1} welcome ${!color2} user>"