Как включить команды в PS1 Bash без расчёта длины строки?

13

Тонин указал на ошибку в моей подсказке по умолчанию . Минимальный пример:

  1. Установите PS1:

    PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s $(tput setaf 1) $exit_code $(tput sgr0) " ")$ '

    На этом этапе подсказка выглядит так:

    $ 
  2. Теперь запустите вывод кода выхода, выполнив:

    false

    Теперь подсказка содержит код завершения красным цветом в начале строки:

    1 $ 
  3. Нажмите Ctrl- r.
  4. Типа "ложь". Теперь подсказка содержит только поиск:

    (reverse-i-search)`false': false
  5. Нажмите Enter.

Полученная история терминала теперь содержит следующее:

1 $ch)`false': false

Ожидаемый результат:

1 $ false

Таким образом, кажется, что результаты поиска в истории смешаны с подсказкой и скрывают фактическую команду, которая была выполнена.

Я попытался обойти это с помощьюPROMPT_COMMAND :

set_exit_code() {
    exit_code=$?
    [[ $exit_code -eq 0 ]] || printf %s $(tput setaf 1) $exit_code $(tput sgr0) " "
}
set_bash_prompt() {
    PS1='$(set_exit_code)$ ' # Double quotes give the same result
}
PROMPT_COMMAND=set_bash_prompt

Похоже, это не работает - после поиска и запуска строка выглядит точно так же, как и раньше.

Как я могу это исправить?

l0b0
источник
1
Похоже, что это продолжение unix.stackexchange.com/a/71012
manatwork

Ответы:

8

Я нашел ответ на askubuntu.com . @qeirha упомянул, что вы должны сказать bash, что последовательность символов не должна учитываться в длине приглашения, и вы делаете это, заключая ее в \[ \]. Основываясь на приведенном примере, вот одно решение:

red=$(tput setaf 1)

reset=$(tput sgr0)

[ "$PS1" = "\\s-\\v\\\$ " ] && PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s \[$red\] $exit_code \[$reset\] " ")$ '
Тимоти Мартин
источник
Не нужно идти, чтобы попросить об этом Ubuntu . У нас уже есть достаточно ответов на этот вопрос и здесь.
manatwork
Спасибо за совет @manatwork! Я хотел отдать должное за объяснение и предоставил ссылку в качестве любезности.
Тимоти Мартин
Предоставление кредита не является проблемой. Но, говоря о проблеме: обратные слэши без экранирования раньше исчезали из Markdown, поэтому ваш простой \ [стал [в вашем посте, таким образом, отображаемый код не функционировал, вставив его в терминал. Этого можно избежать, используя встроенный код или разметку кодового блока. ( Как мне отформатировать мои сообщения, используя Markdown или HTML? )
manatwork
1
D'о! Я уже исправил ту же проблему для другого PS1кода, почему я ее не увидел?
10
1
PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s \[$(tput setaf 1)\] $exit_code \[$(tput sgr0)\] " ")$ '

(Извините, здесь нет объяснения. См. Как правильно настроить PS1? Или любой другой вопрос о проблемах с расчетом длины строки и \[... \])

оборота манатворк
источник
Ко второму вопросу @ l0b0 я добавлю, что с использованием PS1 все \[...\]работает нормально, если вы можете поместить весь код, который вы хотите сгенерировать, в одну строку. Однако, если вы хотите разделить ваш код на маленькие функции, вы попадаете в точку, где вы не можете поместить начальную и конечную скобки в одну строку / функцию. И это нарушает перенос строк. Если вы не прибегаете к использованию PROMPT_COMMANDдля пересчета вашего PS1при каждом запросе.
Тонин
1

Расширяя ответ @manatwork, но сохраняя код, разделяющий PS1вычисления в разных функциях, вы можете написать приглашение следующим образом:

set_exit_code() {
    exit_code=$?
    [[ $exit_code -eq 0 ]] || printf "\[$(tput setaf 1)\] $exit_code \[$(tput sgr0)\] "
}
set_bash_prompt() {
    PS1="$(set_exit_code)$ " # with double quotes!
}
PROMPT_COMMAND=set_bash_prompt

Двойные кавычки обязательны как при настройке, так PS1и при использовании printfв функции.

Tonin
источник
Для использования в будущем используйте bash-функцию .bashrc- не помещайте код в отдельный файл и вызывайте его.
starbeamrainbowlabs