web-dev-qa-db-fra.com

BASH et comportement de retour chariot

J'ai une petite question.
Est-il normal que bash (j'utilise 4.4.11) n'affiche pas les lignes/textes séparés/fin avec _ \r?

J'ai été un peu surpris de voir ce comportement:

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

Mais le texte "bonjour encore" est toujours là, en quelque sorte "caché":

$ 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

Et dès que nous jouons avec bash, c'est bien ... Mais est-ce un risque potentiel pour la sécurité? Et si le contenu de la variable "a" venait du monde extérieur et incluait de "mauvaises commandes" au lieu de juste bonjour?

Un autre test, un peu incertain cette fois:

$ 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>

Imaginez un rm caché au lieu d'un ls caché.

Même comportement lors de l'utilisation d'écho -e:

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

Est-ce moi qui fait quelque chose de mal ...?

11
George Vasiliou

Votre echo "$a" imprime "bonjour", puis revient au début de la ligne (qui est ce que \r fait), imprime "encore", revient en arrière, imprime "george", revient en arrière et passe à la ligne suivante (\n). Tout est parfaitement normal, mais comme le souligne chepner , cela n'a rien à voir avec Bash: \r et \n sont interprétés par le terminal, pas par Bash (c'est pourquoi vous obtenez la sortie complète lorsque vous dirigez la commande vers od).

Vous pouvez mieux voir cela avec

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

car cela laissera la fin du texte écrasé:

georgen,o

Cependant, vous ne pouvez pas vraiment l'utiliser pour masquer les commandes, uniquement leur sortie (et uniquement si vous pouvez être sûr d'écraser avec suffisamment de caractères), à moins d'utiliser eval comme vous le montrez (mais en utilisant eval n'est généralement pas recommandé). Une astuce plus dangereuse est en utilisant CSS pour masquer les commandes destiné à être copié et collé à partir de sites Web.

20
Stephen Kitt

Dans le monde Unix, un retour chariot (généralement codé comme \r dans les langages de programmation) est un caractère de contrôle banal. Vous pouvez avoir des retours chariot à l'intérieur d'une ligne de texte, comme tout autre caractère en dehors d'un saut de ligne (également appelé nouvelle ligne ), qui marque la fin d'une ligne.

En particulier, dans un script bash, un retour chariot est un caractère constituant Word ordinaire, comme les lettres et les chiffres. Tout effet spécial du retour de transport provient du terminal et non du Shell.

Un retour chariot est un caractère de contrôle . Lorsque vous l'imprimez sur un terminal, au lieu d'afficher un glyphe , le terminal effectue un effet spécial. Pour un retour chariot, l'effet spécial est de déplacer le curseur au début de la ligne courante. Ainsi, si vous imprimez une ligne contenant un retour chariot au milieu, l'effet est que la seconde moitié est écrite sur la première moitié.

Plusieurs autres caractères de contrôle ont des effets spéciaux: le caractère de retour arrière déplace le curseur vers la gauche d'une position. Le caractère de cloche amène le terminal à émettre un son ou à attirer autrement l'attention de l'utilisateur. Le caractère d'échappement commence une séquence d'échappement qui peut avoir toutes sortes d'effets spéciaux.

Si vous affichez une sortie non approuvée, vous devez nettoyer ou échapper les caractères de contrôle. Non seulement les retours de chariot, mais aussi plusieurs autres, en particulier le caractère d'échappement, qui peuvent provoquer toutes sortes de mauvais effets. Voir Le "cat-ing" un fichier peut-il être un risque potentiel pour la sécurité? et Comment éviter les attaques de séquence d'échappement dans les terminaux? pour plus d'informations sur le sujet.

Vous pouvez afficher les retours chariot dans une variable bash en utilisant la fonction printf avec un %q format.

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

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

Sources et lectures complémentaires:

0
nuwandame