O prompt do terminal não está sendo encapsulado corretamente

171

Eu tenho um problema em que, se eu digitar comandos muito longos no bash, o terminal não renderizará o que estou digitando corretamente. Eu esperaria que, se tivesse um comando como o seguinte:

username@someserver ~/somepath $ ssh -i /path/to/private/key
myusername@something.someserver.com

O comando deve renderizar em duas linhas. Em vez disso, ele geralmente se espalha e começa a escrever por cima do meu prompt, mais ou menos assim:

myreallylongusername@something.somelongserver.comh -i /path/to/private/key

Se eu decidir voltar e alterar algum argumento, não há como dizer onde o cursor aparecerá, às vezes no meio do prompt, mas geralmente na linha acima de onde estou digitando.

Diversão adicional acontece quando quando eu Uppara um comando anterior. Eu tentei isso no gnome-terminal e terminator e no i3 e Cinnamon. Alguém sugeriu que era o meu prompt, então aqui está:

\[\033[01;32m\]\u:\[\033[01;34m\] \W\033[01;34m \$\[\033[00m\]

Ctrll,, resete cleartodos fazem o que dizem, mas quando digito o comando novamente, ou Upacontece o mesmo.

Eu verifiquei e checkwinsizeestá ativado no bash. Isso acontece em 80x24 e em outros tamanhos de janela.

Isso é apenas algo que eu aprendo a conviver? Existe algum pedaço de magia que eu deveria saber? Decidi usar apenas um prompt muito curto, mas isso não resolve o problema.

Muricula
fonte
1
Então, usando o comando env -i bash --norccorrige-o. As combinações $ COLUMNS e $ LINES. Isso significa que há algo engraçado no meu .bashrc?
Muricula
Então, comentei meu .bashrc e acabei isolando meu prompt como a parte problemática, especificamente a sintaxe de coloração envolvida. O que há de errado com o PS1 acima?
Muricula
1
\[\033[01;32m\]\u: \[\033[01;34m\]\W \[\033[01;34m\] \$ \[\033[0m\]parece evitar a estranheza no comportamento -, mas não sei se ele respeita o seu prompt de originais completamente ...
1
De acordo com esta resposta no serverfault , usetput smam
Samveen 23/10

Respostas:

189

Seqüências não imprimíveis devem estar entre \[e\] . Olhando para o seu PS1, ele tem uma sequência não revelada depois \W. Mas, a segunda entrada é redundante e repete a instrução anterior "1; 34" .

\[\033[01;32m\]\u:\[\033[01;34m\] \W\033[01;34m \$\[\033[00m\]
                  |_____________|               |_|
                         |                       |
                         +--- Let this apply to this as well.

Como tal, isso deveria ter a intenção de colorir:

\[\033[1;32m\]\u:\[\033[1;34m\] \W \$\[\033[0m\]
                               |_____|
                                  |
                                  +---- Bold blue.

Manter o "original" também deve funcionar:

\[\033[1;32m\]\u:\[\033[1;34m\] \W\[\033[1;34m\] \$\[\033[0m\]
                                  |_|         |_|
                                   |           |
                                   +-----------+-- Enclose in \[ \]

Editar:

A razão para o comportamento é porque bashacredita que o prompt é mais longo do que realmente é. Como um exemplo simples, se alguém usar:

PS1="\033[0;34m$"
       1 2345678

Acredita-se que o prompt tenha 8 caracteres e não 1. Como tal, se a janela do terminal tiver 20 colunas, depois de digitar 12 caracteres, acredita-se ter 20 caracteres e contornar. Isso também é evidente se alguém tentar fazer backspace ou Ctrl+u. Para na coluna 9.

No entanto, ele também não inicia uma nova linha, a menos que esteja na última coluna, como resultado, a primeira linha é substituída.

Se alguém continuar digitando, a linha deve passar para a próxima linha após 32 caracteres.

Runium
fonte
Se você tem - ou alguém - tem uma explicação sobre o que exatamente na sequência original fez com que a linha se repitasse, eu estaria interessado em saber disso. Também marcar com +1 como você mostrou isso visualmente.
1
@ illuminÉ: Ainda não olhou para a fonte, mas adicionou uma atualização com uma nota sobre o comportamento da observação.
Runium
Caso esteja enfrentando algum problema, você pode usar este site para criar um novo - bashrcgenerator.com
divinedragon
Isso é incrível, obrigado @Runium - você se importaria em compartilhar como sabia disso? Eu adoraria encontrar alguma documentação sobre isso.
Nycynik 27/03
2
@nycynik: Observação. Eu acho que o mais próximo de documentação sobre isto é o código fonte ...
Runium
83

Tem a ver principalmente com o tamanho da janela assumida pelo terminal não é o mesmo que o tamanho real da janela. Se você estiver usando o bash, tente isso.

$ shopt checkwinsize

Se você não receber

checkwinsize    on

Em seguida, ative-o com

$ shopt -s checkwinsize

Em seguida, tente executar outro comando (como ls) ou redimensionar a janela uma vez, o acima funciona para mim o tempo todo.

Para os sistemas Redhat, em particular, o problema geralmente é causado pela configuração incorreta ~/.bashrcpara não ligar /etc/bashrc. Normalmente, o bash carrega o ~/.bashrcque é esperado chamar /etc/bashrc, que por padrão contém shopt -s checkwinsize.

saketrp
fonte
Teve o mesmo problema com o OS X, aparentemente, se você chamar "login" para iniciar seu terminal, ele inicia o bash de uma maneira que lê / etc / bashrc, mas se você simplesmente ligar diretamente para o bash, o ~ / .bashrc não origine as coisas por padrão para obter o efeito de quebra automática. Obrigado!
Rogerdpack # 11/15
Isso funcionou para mim também. As cores não estavam ativadas neste servidor em particular, chamando corretamente /etc/bashrc, tudo o mais estava bom ... Acontece que essa é a causa dos problemas de empacotamento.
dhaupin
Veja também unix.stackexchange.com/a/61608/2221
astrojuanlu
Parece uma boa solução. Mas não funciona na minha sessão ssh. Não sei por que. Eu executei o comando shopt -s checkwinsizena sessão ssh. Mas a embalagem persiste.
Qiang Xu
Este era precisamente o meu problema - um usuário .bashrc não estava chamando / etc / bashrc e, portanto, estava fazendo uma bagunça.
Sobrique
9

Como mencionado em outras respostas, sequências não imprimíveis como \e[0;30mdevem ser envolvidas \[...\].

Além disso (e o que ainda não vi mencionado), parece que ele \r\ndeve estar fora do \[...\]se você tiver um prompt de várias linhas. Levei algumas tentativas e erros para finalmente descobrir isso.

Geraden
fonte
8

Uma vez eu li em algum lugar (não sei mais onde) que usar \001e ao \002invés de \[e \]pode resolver esse problema. Isso fez por mim.

A propósito, definir PS1 não precisa parecer feio.

green="\001$(tput setaf 2)\002"
blue="\001$(tput setaf 4)\002"
dim="\001$(tput dim)\002"
reset="\001$(tput sgr0)\002"

PS1="$dim[\t] " # [hh:mm:ss]
PS1+="$green\u@\h" # user@host
PS1+="$blue\w\$$reset " # workingdir$

export PS1
unset green blue dim reset
phil294
fonte
2
Meu PS1 chama um comando que imprime seqüências de escape causando o problema do OP. Somente esta solução corrige o problema para mim.
RickMeasham
6

Isso soa como um problema nas configurações da variável COLUMNS& LINESambiente. Quando você redimensionar a janela eles estão tipicamente definido automaticamente pelo gnome-terminal (creio eu) você pode forçá-los a ser definido manualmente, emitindo o comando resize.

Exemplo

Se eu redimensionar meu terminal gnome para 79x17, minhas variáveis ​​aparecerão assim:

$ echo $COLUMNS; echo $LINES
79
17

Eu posso forçá-lo assim:

$ resize
COLUMNS=79;
LINES=17;
export COLUMNS LINES;
slm
fonte
1
Interessante, mas não ajuda.
Muricula
1
Isso corrigiu meu problema, que não estava quebrando as linhas corretamente depois que eu executei o comando "tela". Obrigado!!
Nukeguy 30/05
5

Para evitar quebra automática, você também pode aumentar o número de colunas usando, por exemplo,

stty columns 120
ismael
fonte
1
não é uma idéia muito boa, sujou-se vim brutalmente
phil294
3

Além disso, o mesmo problema pode ser causado pelo uso de símbolos unicode largos (como em https://stackoverflow.com/a/34812608/1657819 ). Aqui está o trecho que está causando o problema (lembre-se das seqüências de cores de escape apropriadas $Greene $Red):

FancyX='\342\234\227'
Checkmark='\342\234\223'


# Add a bright white exit status for the last command
PS1="$White\$? "
# If it was successful, print a green check mark. Otherwise, print
# a red X.
if [[ $Last_Command == 0 ]]; then
    PS1+="$Green$Checkmark "
else
    PS1+="$Red$FancyX "
fi

O Bash não pode calcular o comprimento corretamente, portanto, a maneira mais fácil seria escapar de duas das três partes desses símbolos largos.

FancyX='\[\342\234\]\227'
Checkmark='\[\342\234\]\223'
O padrinho
fonte
Faz sentido. O que eu acho é que o bash conta caracteres. Como o X recebe um caractere, mas é escrito como 3, é necessário incluir 2 deles para corrigir a contagem. A resposta @blauhirn também explica como fazer em uma função com \001e \002.
akostadinov 24/01
Para sua informação, é assim que você descobre como
gerar