Sequência de escape não imprimível: quando?

6

Recentemente, tenho jogado muito com cor no terminal e, portanto, com sequências de escape também. Eu li as partes relevantes do manpage Bash, juntamente com inúmeras páginas úteis na Net.

Eu tenho mais do que eu quero trabalhar; uma cor agradável Bash prompt, por exemplo. Dito isso, ainda estou um pouco confuso sobre quando devo usar (ou preciso usar) os caracteres "sequência de escape sem impressão". Aqueles seriam \[ e \] .

Se eu não usá-los no PS1 ao definir meu prompt, meu prompt definitivamente não será exibido corretamente. Se eu usá-los, tudo está bem. Bom.

Mas, fora do PS1, eles não parecem funcionar da mesma maneira. Por exemplo, para tornar os scripts mais legíveis, defini uma variável $RGB_PURPLE , que é definida por meio de uma função simples c8_rgb() . O resultado final é que a variável contém o valor \[\e[01;38;05;129m\] que ativa uma cor de primeiro plano púrpura em negrito.

Quando eu uso essa variável no PS1, ela faz o que eu espero. Se eu usá-lo via printf ou echo -e , "metade" funciona. O comando printf "${RGB_PURPLE}TEST${COLOR_CLR}\n" (onde COLOR_CLR é a seqüência de escape para redefinir propriedades de texto) resulta na seguinte exibição: \[\]TEST\[\] , em que tudo, exceto o primeiro \[ e o final \] , são exibidos em roxo.

Por que a diferença? Por que esses suportes são impressos em vez de serem processados pelo terminal? Eu esperava que eles fossem tratados da mesma forma quando impressos como parte do prompt, quando impressos por outros meios. Eu não entendo a mudança.

Parece, empiricamente, que esses caracteres devem ser usados dentro da definição do prompt, enquanto não devem ser usados em praticamente todos os outros casos. Isso dificulta o uso de uma função comum, como minha função c8_rgb() mencionada acima, para manipular a geração e a saída da seqüência de escape, pois a função não pode saber se seu resultado estará em uma configuração de prompt ou em outro lugar.

E uma rápida pergunta relacionada: echo -e e printf são essencialmente os mesmos no que diz respeito à saída de seqüências de escape? Eu normalmente uso printf, mas há algum motivo para favorecer um sobre o outro?

Alguém pode explicar essa aparente diferença sutil? Existem outras esquisitices que eu deveria estar ciente ao usar seqüências de escape (geralmente apenas para cor) no terminal? Obrigado!

    
por JetpackJohn 27.09.2014 / 09:18

3 respostas

6

A "seqüência de escape não imprimível" é necessária ao usar caracteres não imprimíveis em $ PS1, porque o bash precisa saber a posição do cursor para que a tela possa ser atualizada corretamente quando você editar a linha de comando. Bash faz isso contando o número de caracteres no prompt $ PS1 e então esse é o número da coluna em que o cursor está.

No entanto, se você colocar sequências não impressas em $ PS1, essa contagem estará incorreta e a linha poderá ficar confusa se você editar a linha de comando. Daí a introdução dos marcadores \[ e \] para indicar que os bytes incluídos não devem ser contados.

    
por 27.09.2014 / 11:29
2

Algo como ␛[01;38;05;129m , em que o primeiro caractere é o caractere de escape ASCII (U + 0027), é uma seqüência de escape de terminal. Ele instrui o terminal a começar a exibir texto em negrito e piscando em cor 129. \e é sintaxe bash para o caractere de escape (dentro de $'…' , em PS1 , em echo -e e em printf ).

\[ e \] não são sequências de escape de terminal, são sequências de escape de prompt do bash. Eles são interpretados por bash, não enviados para o terminal. Sua finalidade é dizer ao bash que o que há entre os caracteres não são impressos, de modo que a largura do prompt seja realmente o número de caracteres que não estão dentro de \[…\] . O Bash precisa saber a largura do prompt para calcular a posição do cursor no editor de linhas.

Sua função não deve produzir \[…\] se for usada fora das strings de prompt. Inclua \[ e \] diretamente na string de prompt.

    
por 28.09.2014 / 02:34
2

Eu encontrei uma solução suficiente usando as seqüências de escape octal , e usando os formulários readline dos caracteres delimitadores. PS1, echo -e e printf fazem a coisa certa exatamente com as mesmas strings. Eu testei isso no Bash 4 no OSX e no Bash 3 no Linux.

Eu tenho a ideia para \ 001 e \ 002 de uma resposta aqui: link

Exemplo:

$ TextGreen='
$ TextGreen='%pre%13[0;32m%pre%2'
$ TextReset='%pre%13[0m%pre%2'
$ SomeString="${TextGreen}prompt_stuph${TextReset} \$ "
$ #
$ # now all of the following work as expected
$ #
$ PS1="$SomeString"
$ printf "$SomeString"
$ echo -e "$SomeString"
13[0;32m%pre%2' $ TextReset='%pre%13[0m%pre%2' $ SomeString="${TextGreen}prompt_stuph${TextReset} \$ " $ # $ # now all of the following work as expected $ # $ PS1="$SomeString" $ printf "$SomeString" $ echo -e "$SomeString"
    
por 01.01.2018 / 00:22