Подтвердить что ты не робот

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

4b9b3361

Ответ 1

Использование eval является классическим решением, но bash имеет лучшее (более легко управляемое, менее blunderbuss-подобное) решение:

  • ${!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 очень нестандартная, но просто выгружает свои данные в шестнадцатеричном формате с печатными символами, показанными справа. Поскольку 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>"