Sobreposição do histórico do cliente bash personalizado

Sobreposição do histórico do cliente bash personalizado

Estou escrevendo um cliente para realizar várias tarefas no servidor zimbra via ssh e encontrei um pequeno obstáculo. Aqui está o código:

#!/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

NOTA: se você executar este script, ele criará o arquivo de histórico (.zmcli_history) em seu diretório inicial.

Tudo funciona como planejado e o histórico está todo lá, mas muitas vezes a parte de algum comando anterior (geralmente longo) permanece enquanto continuo a percorrer o histórico. Essa parte do comando atua como parte do prompt para o resto da sessão, a menos que eu pressione CTRL+L, que limpa a tela e a redefine ao normal. Eu li muitas postagens que ajudaram pessoas que tiveram esse problema em seu terminal bash. O problema deles era que o PS1 estava formatado incorretamente e o bash ficou confuso sobre o comprimento da string do prompt. Provavelmente é algo semelhante aqui, mas essas soluções não funcionam, porque o comando read não pode usar caracteres de escape como echo pode (\ e).

Consegui encontrar uma maneira de escapar das sequências de cores usando escapes literais (CTRL+V ESCAPE no modo de inserção do vim). Então as cores funcionam, mas estou preso a esse problema de histórico.

Coisas que tentei:

  • substituição de comando :: escreva e escape os códigos de cores de forma que echo -e possa imprimi-los e, em seguida, faça eco no comando de leitura $(echo -e '\e[33m'). Ainda vendo as cores, mas não ajudou no problema de histórico
  • adicionando [e] escapado em torno dos códigos de cores
  • colocando todo o prompt com códigos de cores em um comando echo separado que vem antes do comando read. A desvantagem é que não consigo desligar a formatação até depois do comando de leitura (em outro eco), o que significa que todo o prompt e comando estarão em negrito e coloridos. Além disso, se eu pressionar CTRL+L agora, até o prompt será limpo e só ficarei com o cursor

Por fim, como não consigo descartar o histórico, tentei descartar as cores. Mas então fica impossível diferenciar rapidamente entre comandos e saídas.

Você pode replicar o problema iniciando o script e inserindo de 10 a 15 comandos longos (sem sentido). Depois disso, tente rolar para cima e para baixo no histórico e você verá do que estou falando.

Alguém sabe uma maneira de fazer isso funcionar?

Responder1

Seu roteiro,como isso é, não me permitiu replicar o problema. Só depois de habilitar as cores e tal readline comecei a ficar confuso. Para que conste, eu habilitei essas coisas com

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

E é verdade \[e \]não ajuda comoeles fazem em caso dePS1.

Mas então eu encontreiesta resposta. Ele lê

Abri info readlinee encontrei:

[…]
Os aplicativos podem indicar que o prompt contém caracteres que não ocupam espaço físico na tela quando exibidos, colocando uma sequência de tais caracteres entre colchetes com os marcadores especiais RL_PROMPT_START_IGNOREe RL_PROMPT_END_IGNORE(declarados em readline.h. Isso pode ser usado para incorporar sequências de escape específicas do terminal em prompts.

Como diz o texto que procuro RL_PROMPT_START_IGNOREe RL_PROMPT_END_IGNOREdefinição readline.he encontrei a seguir:

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

Isso me levou ao seguinte:

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

Funciona perfeitamente.

informação relacionada