Пользовательское перекрытие истории клиента bash

Пользовательское перекрытие истории клиента bash

Я пишу клиент для выполнения различных задач на сервере zimbra через ssh, и у меня возникла небольшая загвоздка. Вот код:

#!/bin/bash
set -e
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
export HISTCONTROL=ignoreboth

# History management
if [ -f $HOME/.zmcli_history ]; then
  history -r $HOME/.zmcli_history
else
  touch $HOME/.zmcli_history
  history -r $HOME/.zmcli_history
fi
trap "history -a $HOME/.zmcli_history && echo -e '\nExiting now.\n'" exit

# Styling
yellow='[33m'
bold='[1m'
off='[0m'

echo

# Client
while :; do
  read -ep "$bold${yellow}zimbra_cli[${off}server_domain$bold${yellow}]> $off" comm
  history -s "$comm"
done

ПРИМЕЧАНИЕ: если вы выполните этот скрипт, он создаст файл истории (.zmcli_history) в вашем домашнем каталоге.

Все работает так, как задумано, и история вся на месте, но часто часть какой-то (обычно длинной) предыдущей команды остается, когда я продолжаю прокручивать историю. Эта часть команды действует как часть приглашения для остальной части сеанса, если только я не нажму CTRL+L, что очистит экран и сбросит его в нормальное состояние. Я прочитал много сообщений, которые помогли людям, у которых была эта проблема в их терминале bash. Их проблема заключалась в том, что PS1 был неправильно отформатирован, и bash путался с длиной строки приглашения. Вероятно, здесь что-то похожее, но эти решения не работают, потому что команда read не может использовать эти экранированные символы, как echo может (\e).

Мне удалось найти способ экранирования цветовых последовательностей с помощью буквальных экранирований (CTRL+V ESCAPE в режиме вставки vim). Итак, цвета работают, но я застрял с этой проблемой истории.

Что я пробовал:

  • подстановка команд :: напишите и экранируйте цветовые коды таким образом, чтобы echo -e могла их вывести, а затем вывести их в команде чтения $(echo -e '\e[33m'). Цвета все еще видны, но это не помогло решить проблему с историей
  • добавление экранированных [ и ] вокруг цветовых кодов
  • помещая всю подсказку с цветовыми кодами в отдельную команду echo, которая идет перед командой read. Недостаток в том, что я не могу отключить форматирование до команды read (в другой команде echo), что означает, что вся подсказка и команда будут жирными и цветными. Кроме того, если я сейчас нажму CTRL+L, даже подсказка будет очищена, и у меня останется только курсор

Наконец, поскольку я не могу удалить историю, я попытался удалить цвета. Но тогда становится невозможно быстро различать команды и вывод.

Вы можете воспроизвести проблему, запустив скрипт и введя 10-15 длинных (бессмысленных) команд. После этого попробуйте прокрутить историю вверх и вниз, и вы поймете, о чем я говорю.

Кто-нибудь знает, как это сделать?

решение1

Ваш сценарий,как есть, не позволили мне воспроизвести проблему. Только после включения цветов и прочей readline начал путаться. Для справки, я включил эти вещи с

# Styling
yellow=$'\e[33m'
bold=$'\e[1m'
off=$'\e[0m'

И это правда \[и \]не помогает какони делают в случаеPS1.

Но потом я обнаружил,этот ответ. Он читает

Я открываю info readlineи вижу:

[…]
Приложения могут указывать, что приглашение содержит символы, которые не занимают физического пространства на экране при отображении, заключая последовательность таких символов в скобки со специальными маркерами RL_PROMPT_START_IGNOREи RL_PROMPT_END_IGNORE(объявленными в readline.h. Это может использоваться для встраивания управляющих последовательностей, специфичных для терминала, в приглашения.

Как говорится в тексте, который я искал RL_PROMPT_START_IGNOREи RL_PROMPT_END_IGNOREопределение, readline.hи нашел следующее:

/* Definitions available for use by readline clients. */
#define RL_PROMPT_START_IGNORE  '\001'
#define RL_PROMPT_END_IGNORE    '\002'

Это привело меня к следующему:

# Styling
yellow=$'\1\e[33m\2'
bold=$'\1\e[1m\2'
off=$'\1\e[0m\2'

Работает безупречно.

Связанный контент