BASH et comportement de retour chariot


11

J'ai une petite question.
Est-il normal que bash (j'utilise 4.4.11) n'affiche pas les lignes / texte séparés / fin avec plain \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 caché rmau lieu d'un caché ls.

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 ...?

Réponses:


20

Vos echo "$a"impressions "bonjour", puis retourne au début de la ligne (ce qui est le \rcas), imprimer "à nouveau", 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: \ret \nsont interprétés par le terminal, pas par Bash (c'est pourquoi vous obtenez la sortie complète lorsque vous dirigez la commande 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

Vous ne pouvez pas vraiment utiliser cela pour masquer les commandes, seulement leur sortie (et seulement si vous pouvez être sûr d'écraser avec suffisamment de caractères), sauf si vous utilisez evalcomme vous le montrez (mais l'utilisation evaln'est généralement pas recommandée). Une astuce plus dangereuse consiste à utiliser CSS pour masquer les commandes destinées à être copiées et collées à partir de sites Web.


Assez clair, merci. J'ai eu la chance / la malchance d'utiliser un dernier mot dans mon test capable d'écraser complètement les deux mots précédents.
George Vasiliou

2
Notez cependant que cela n'a rien à voir avec bash; c'est entièrement au terminal comment "afficher" le retour chariot, ou comment afficher les caractères écrasés. Par exemple, il serait parfaitement valable qu'un terminal s'affiche -\r|comme quelque chose ressemblant à un signe plus, plutôt qu'à un simple tuyau.
chepner

@chepner Bon à savoir! Merci d'avoir partagé. Je pensais que c'était juste un comportement bash.
George Vasiliou

@GeorgeVasiliou Non, bashécrit juste des octets dans un fichier; c'est à celui qui lit ces octets de les interpréter.
chepner

Nitpick: printfqui est un bash intégré dans la commande (bien qu'il existe aussi comme un exécutable autonome), interprète la \r(une séquence de deux octets: 0x5cet 0x72et produit le retour de chariot (un seul octet: 0x0d.) Ensuite, oui, le terminal interprète l'octet 0x0dd'une manière particulière, mais il ne l' interprète pas la chaîne d' origine \r.
Suzanne Dupéron

6

Dans le monde Unix, un retour chariot (généralement codé comme \rdans 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é retour à la ligne ), qui marque la fin d'une ligne.

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

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 personnage 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 chariot, mais aussi plusieurs autres, en particulier le caractère d'échappement, qui peuvent provoquer toutes sortes de mauvais effets. Voir «Attraper» un fichier peut-il représenter un risque de sécurité potentiel? et Comment éviter les attaques de séquence d'échappement dans les terminaux? pour en savoir plus sur le sujet.


0

Vous pouvez afficher les retours chariot dans une variable bash en utilisant la printffonction avec un %qformat.

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.