BASH e comportamento de retorno de carro

11

Eu tenho uma pergunta rápida.
É normal que o bash (eu estou usando o 4.4.11) não esteja exibindo linhas / texto que é separado / final com simples \r?

Fiquei um pouco surpreso ao ver esse comportamento:

$ a=$(printf "hello\ragain\rgeorge\r\n")
$ echo "$a"
george

Mas o texto "olá novamente" ainda está lá, de alguma forma "oculto":

$ echo "$a" |od -w32 -t x1c
0000000  68  65  6c  6c  6f  0d  61  67  61  69  6e  0d  67  65  6f  72  67  65  0d  0a
          h   e   l   l   o  \r   a   g   a   i   n  \r   g   e   o   r   g   e  \r  \n

E assim que brincamos com o bash, tudo bem ... Mas isso é um risco potencial à segurança? E se o conteúdo da variável "a" vier do mundo exterior e incluir "comandos ruins" em vez de apenas olá?

Outro teste, um pouco inseguro desta vez:

$ a=$(printf "ls;\rGeorge\n")
$ echo "$a"
George
$ eval "$a"
0                   awkprof.out       event-tester.log  helloworld.c      oneshot.sh         rightclick-tester.py  tmp                    uinput-simple.py
<directory listing appears with an error message at the end for command George>

Imagine um oculto em rmvez de um oculto ls.

Mesmo comportamento ao usar echo -e:

$ a=$(echo -e "ls;\rGeorge\r\n"); echo "$a"
George

Sou eu que faço algo errado ...?

George Vasiliou
fonte

Respostas:

20

Suas echo "$a"impressões "olá", voltam ao início da linha (que é o que \rfaz), imprima "novamente", voltam novamente, imprimem "george", voltam novamente e passam para a próxima linha ( \n). É tudo perfeitamente normal, mas, como aponta o chepner , isso não tem nada a ver com o Bash: \re \né interpretado pelo terminal, não pelo Bash (e é por isso que você obtém a saída completa ao canalizar o comando od).

Você pode ver isso melhor com

$ a=$(printf "hellooooo\r  again,\rgeorge\r\n")
$ echo "$a"

pois isso deixará o final do texto substituído:

georgen,o

Você realmente não pode usá-lo para ocultar comandos, apenas a saída deles (e somente se você tiver a certeza de sobrescrever com caracteres suficientes), a menos que esteja usando evalo que mostra (mas o uso evalgeralmente não é recomendado). Um truque mais perigoso é usar CSS para mascarar comandos destinados a serem copiados e colados a partir de sites.

Stephen Kitt
fonte
Claro o suficiente, obrigado. Eu tive sorte / azar de usar uma última palavra no meu teste capaz de sobrescrever completamente as duas palavras anteriores.
9788 George Vasiliou #
2
Observe que isso realmente não tem nada a ver com bash; depende inteiramente do terminal como "exibir" o retorno de carro ou como exibir os caracteres substituídos. Por exemplo, seria perfeitamente válido que um terminal fosse exibido -\r|como algo parecido com um sinal de mais, em vez de apenas um tubo.
chepner
@chepner É bom saber! Obrigado por compartilhar. Eu pensei que este era apenas um comportamento bash.
George Vasiliou
@GeorgeVasiliou Não, bashapenas grava bytes em um arquivo; cabe a quem esses bytes interpretá-los.
Chepner #
Nitpick: printf, que é uma festa comando interno (embora também existe como um executável autónomo), interpreta a \r(uma sequência de dois bytes: 0x5ce 0x72e produz o retorno do carro (um único byte: 0x0d.) Então, sim, o terminal interpreta o byte 0x0dde uma maneira especial, mas não interpretar a string original \r.
Suzanne Dupéron
6

No mundo Unix, um retorno de carro (comumente codificado como \rem linguagens de programação) é um caractere de controle normal. Você pode obter retornos de carro dentro de uma linha de texto, como qualquer outro caractere, além de um feed de linha (também chamado de nova linha ), que marca o final de uma linha.

Em particular, em um script bash, um retorno de carro é um caractere comum da palavra constituinte, como letras e dígitos. Qualquer efeito especial do retorno de carro vem do terminal, não do invólucro.

Um retorno de carro é um caractere de controle . Quando você o imprime em um terminal, em vez de exibir um glifo , o terminal realiza algum efeito especial. Para um retorno de carro, o efeito especial é mover o cursor para o início da linha atual. Portanto, se você imprimir uma linha que contenha um retorno de carro no meio, o efeito será que a segunda metade será gravada na primeira metade.

Vários outros caracteres de controle têm efeitos especiais: o caractere de backspace move o cursor para a esquerda em uma posição. O caractere de campainha faz com que o terminal emita um som ou atraia a atenção do usuário. O caractere de escape inicia uma sequência de escape que pode ter todos os tipos de efeitos especiais.

Se você exibir uma saída não confiável, precisará limpar ou escapar dos caracteres de controle. Não apenas retornos de carro, mas também vários outros, em particular o caractere de escape, que pode causar todos os tipos de efeitos negativos. Consulte "Criar um arquivo" pode ser um risco potencial à segurança? e Como evitar ataques de sequência de escape em terminais? para saber mais sobre o assunto.

Gilles 'SO- parar de ser mau'
fonte
0

Você pode visualizar os retornos de carro em uma variável bash usando a printffunção com um %qformato.

$ TESTVAR="$(printf ' Version: 1 \r Build: 20180712 \r Test: 1324')"

$ printf %q $TESTVAR
Version:1$'\r'Build:20180712$'\r'Test:1324

Fontes e leituras adicionais:

nuwandame
fonte