Я пишу клиент для выполнения различных задач на сервере 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'
Работает безупречно.