21

В Bash Prompt (переменная PS1) я вызываю функцию для потенциального добавления текста в приглашение: export PS1="\u@\h \$(my_function) \$ "

Однако функция в приглашении содержит цветовые коды ANSI, которые меняются в зависимости от выходных данных функции (иногда красный, иногда зеленый). Добавление « \[ » в переменную PS1 должно исключить эти коды как непечатные, но если я сделаю echo в функции, « \[ » будет напечатано буквально в приглашении.

Как я могу избежать этих цветовых кодов ANSI из функции для использования в приглашении bash?

4 ответа4

32

Библиотека readline принимает \001 и \002 (ASCII SOH и STX) в качестве разделителей текста, которые нельзя распечатать. Они также работают в любом приложении, которое использует readline.

Из lib/readline/display.c:243 в исходном коде bash :

243 /* Current implementation:
244         \001 (^A) start non-visible characters
245         \002 (^B) end non-visible characters
246    all characters except \001 and \002 (following a \001) are copied to
247    the returned string; all characters except those between \001 and
248    \002 are assumed to be `visible'. */

Специфичные для bash \[ и \] фактически транслируются в \001 и \002 при y.tab.c:7640 .


Примечание. Если вы используете команду printf или echo -e bash , и если ваш текст имеет \001 или \002 непосредственно перед числом, вы обнаружите ошибку bash , из-за которой при обработке восьмеричных кодировок она съедает одну цифру слишком много - то есть \00142 будет интерпретироваться как восьмеричный 014 (за которым следует ASCII "2") вместо правильного восьмеричного 01 (за которым следует ASCII "42"). По этой причине используйте шестнадцатеричные версии \x01 и \x02 .

1

Вот хороший полный ответ. Я должен был сделать намного больше копания, чтобы выяснить, куда должен идти \001 и т.д. Надеюсь это поможет.

# Color prompt for git
reset=$(tput sgr0)
boldgreen=$(tput setaf 2)$(tput bold)
cyan=$(tput sgr0)$(tput setaf 6)
boldred=$(tput setaf 1)$(tput bold)
boldwhite=$(tput setaf 7)$(tput bold)
boldyellow=$(tput setaf 3)$(tput bold)

PARENCLR=$'\001\e[0;36m\002'
BRANCHCLR=$'\001\e[1;33m\002'

alias branchname="git branch 2>/dev/null | grep '*' | sed 's/* \(.*\)/ ${PARENCLR}(${BRANCHCLR}\1${PARENCLR}\)/'"

GIT_STATUS='$(branchname)'

PROMPT_CHAR="\$"
PS1="\[$boldgreen\]\u\[$cyan\]::\[$boldred\]\h \[$cyan\]{\[$boldwhite\].../\W\[$cyan\]}\[$reset\]$GIT_STATUS\[$reset\]$PROMPT_CHAR "

Как я настроил здесь, круглые скобки в git-ветке появляются только в том случае, если вы находитесь в git-ветке, иначе она пустая.

0

Исходя из ответа Гравити, следующие элементы будут включать управляющие последовательности ANSI в ASCII SOH (^A) и STX (^B), которые эквивалентны \[ и \] соответственно:

function readline_ANSI_escape() {
  if [[ $# -ge 1 ]]; then
    echo "$*"
  else
    cat  # Read string from STDIN
  fi | \
  perl -pe 's/(?:(?<!\x1)|(?<!\\\[))(\x1b\[[0-9;]*[mG])(?!\x2|\\\])/\x1\1\x2/g'
}

Используйте это как:

$ echo $'\e[0;1;31mRED' | readline_ANSI_escape

Или же:

$ readline_ANSI_escape "$string"

В качестве бонуса, многократное выполнение функции не приведет к повторному выводу уже сброшенных управляющих кодов.

-2

Если вы хотите использовать их в приглашении, вам нужно сделать \[ . Но если вы хотите использовать его в эхо, вы должны использовать \033[ .

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .