Использование переменных для хранения цветовых кодов терминала для PS1?

33

В моем .bashrc, я использую цветовые коды терминала ANSI, чтобы раскрасить различные биты. Это выглядит так:

PS1='\u@\h:\w\[\033[33m\]$(virtual_env)\[\033[32m\]$(git_branch)\[\033[0m\]$ '

где virtual_envи git_branchbash-функции, которые выводят материал на стандартный вывод.

Теперь, чтобы было легче читать и изменять, я хотел бы хранить цветовые коды в переменных и ссылаться на них, а не встраивать их непосредственно в PS1. Итак, у меня есть несколько переменных, как это:

GREEN="\[\033[32m\]"
YELLOW="\[\033[33m\]"
RESET="\[\033[0m\]"

Я хотел бы иметь возможность написать что-то вроде:

PS1='\u@\h:\w${YELLOW}$(virtual_env)${GREEN}$(git_branch)${RESET}$ '

Но это не работает - цветовые коды отображаются в подсказке, как будто они сбежали. Цвета работают правильно, если я использую двойные кавычки вместо PS1, но тогда подсказка меняется только тогда, когда я это делаю source ~/.bashrc.

Я попробовал другие вещи , которые я видел , что люди делают - используя printf, используя одиночные кавычки для цветов, помещая \[и \]в PS1вместо переменного цвета, но ничего не похоже на работу.

Как я могу использовать переменные для цветовых кодов?

Исмаил Бадави
источник
Можете ли вы дать нам свой .bashrc?
cuonglm
@cuonglm Все ваши .bashrc принадлежат нам? Я покажу себя.
CivFan

Ответы:

20

Решение состоит в том, чтобы заставить оболочку подставлять переменные цвета при определении приглашения, но не функции. Для этого используйте двойные кавычки, как вы изначально пробовали, но избегайте команд, чтобы они не оценивались до тех пор, пока не будет выведено приглашение.

PS1="\u@\h:\w${YELLOW}\$(virtual_env)${GREEN}\$(git_branch)${RESET}$ "

Обратите внимание на \перед $()каждой команды.

Если мы повторим это, мы увидим:

echo "$PS1"
\u@\h:\w\[\033[33m\]$(virtual_env)\[\033[32m\]$(git_branch)\[\033[0m\]$ 

Как видите, переменные цвета были заменены, но не команды.

Патрик
источник
1
Это, похоже, не работает, если $ (git_branch) также пытается печатать, используя $ {YELLOW} и т. Д. Только в этом разделе вы все равно получите все символы [].
ВБ Рид
7

Проблема в том, что ваша переменная GREENсодержит литеральную строку, состоящую из «обратной косой черты, обратной косой черты, нуля, три, три» и так далее. Например, он не содержит управляющий символ ASCII, необходимый для изменения цвета вашего терминала.

Вы можете поместить управляющие символы в GREENYELLOWи RESET) вручную, но гораздо лучше использовать tputво-первых, чтобы вам не нужно было ничего кодировать жестко, и вы будете поддерживать любой тип терминала.

GREEN="$(tput setaf 2)"
YELLOW="$(tput setaf 3)"
RESET="$(tput setaf 0)"

Причина, по которой мир ставит «обратный слеш ноль три три» и т. Д. Непосредственно в PS1том, что интерпретация определенных последовательностей с обратным слешем - это особенность подсказок bash (см. Раздел ПРЕДУПРЕЖДЕНИЕ в руководстве. Эта замена происходит перед расширением параметра, команда тем не менее, подстановка, арифметическое расширение и удаление кавычек не применяются к результатам всех этих других операций.

Celada
источник
5
Делая это таким образом, вы должны обернуть переменные цвета \[\]внутри $PS1. Например: PS1='\u@\h:\w\[${YELLOW}\]'. Если вы этого не сделаете, и в итоге получите длинную команду, которая переносится на следующую строку, вы столкнетесь со всевозможными проблемами. Оболочка использует, \[\]чтобы определить, какие символы нельзя распечатать, поэтому она не учитывает их при расчете длины подсказки. Это необходимо, чтобы он мог правильно нарисовать линию, когда она превышает ширину терминала.
Патрик
Я не знал о tput, спасибо. Я пока воспользуюсь ответом Патрика, но я вернусь к этому, когда у меня будет шанс.
Исмаил Бадави
2

Измените способ заполнения $ GREEN, $ YELLOW и $ RESET:

GREEN="$(echo -e "\033[32m")"
YELLOW="$(echo -e "\033[33m")"
RESET="$(echo -e "\033[0m")"

PS1='\u@\h:\w${YELLOW}$(virtual_env)${GREEN}$(git_branch)${RESET}$ '
Кир
источник
1
Это фактически делает то же самое, что и ответ Селады. Но Celada более портативен в случае, если терминал использует различные коды выхода для настройки цвета. У этого также будет та же проблема с многострочным приглашением.
Патрик
2
В \[…\]бит должен оставаться в приглашении, вы не можете запихнуть его в переменной. Вы полностью удалили его, что приведет к проблемам с отображением (курсор не находится в положении, в котором его ожидает bash).
Жиль "ТАК - перестань быть злым"
Помимо проблем @Patrick, echo -e не является переносимым.
Помощник
1
Непереносимость tput setafдает больше возможностей - не позволяет выбирать из «светлого» набора цветов, например, светло-голубого. Ответ @ Кира, однако, делает.
CivFan