184 votes

Comment supprimer un saut de ligne d'une chaîne en Bash

J'ai la variable suivante.

echo "|$COMMAND|"

qui renvoie

|
REBOOT|

Comment puis-je supprimer ce premier saut de ligne ?

193voto

F. Hauri Points 5893

Remplacement / suppression de caractères dans une chaîne

Sous bash, il existe des bashismes :

La commande tr pourrait être remplacée par le bashisme ${parameter/pattern/string} :

COMMANDE=$'\nREBOOT\r   \n'
echo "|${COMMANDE}|"
|
   OOT
|

echo "|${COMMANDE//[$'\t\r\n']}|"
|REBOOT   |

echo "|${COMMANDE//[$'\t\r\n ']}|"
|REBOOT|

Voir Extension de paramètre et QUOTING dans la page man de bash :

man -Pless\ +/parameter/pattern/string bash

man -Pless\ +/\/pattern bash
man -Pless\ +/\\\'string\\\' bash

man -Pless\ +/^\\\ *Parameter\\\ Exp bash
man -Pless\ +/^\\\ *QUOTING bash
${parameter//pattern/string}
    S'il y a deux barres obliques séparant le paramètre et le motif,
    toutes les correspondances du motif sont remplacées par la chaîne.

En savoir plus...

Comme demandé par @AlexJordan, ceci supprimera tous les caractères spécifiés. Alors que faire si $COMMANDE contient des espaces...

COMMANDE=$'         \n        RE BOOT      \r           \n'
echo "|$COMMANDE|"
|
           BOOT      
|

read -r COMMANDE <<<"${COMMANDE//[$'\t\r\n']}"
echo "|$COMMANDE|"
|RE BOOT|

Explication

En répondant à la question de Vulwsztyn :

Pourquoi cela fonctionne-t-il lorsque le motif est vide ?

Dans ${COMMANDE//[$'\t\r\n ']} :

  • La 1ère barre oblique / signifie : Substitution de motif
  • Le motif est /[$'\r\n '], commence par / puis toutes les correspondances du motif sont remplacées par la chaîne
  • Ensuite, la chaîne est vide.

Éviter fork vers tr pour une seule chaîne !

Comparons :

COMMANDE=$'\nREBOOT\r   \n'
echo ${COMMANDE@Q}
$'\nREBOOT\r \n'

COMMANDE=$(echo $COMMANDE|tr -d '\n\t\r ')
echo ${COMMANDE@Q}
'REBOOT'

Ensuite

time for i in {1..1000};do
    COMMANDE=$'\nREBOOT\r   \n'
    COMMANDE=$(echo $COMMANDE|tr -d '\n\t\r ')
done;echo ${COMMANDE@Q}

réel    0m2.785s
utilisateur    0m2.296s
système     0m0.774s
'REBOOT'

Avec

COMMANDE=$'\nREBOOT\r   \n'
COMMANDE="${COMMANDE//[$'\t\r\n ']}"
echo ${COMMANDE@Q}

time for i in {1..1000};do
    COMMANDE=$'\nREBOOT\r   \n'
    COMMANDE="${COMMANDE//[$'\t\r\n ']}"
done;echo ${COMMANDE@Q}

réel    0m0.006s
utilisateur    0m0.001s
système     0m0.004s
'REBOOT'

Effectuer 1'000 forks vers tr prend plus de 2700ms sur mon hôte, alors que le même travail est effectué en 6ms ( 464.2x plus rapide !! ) en utilisant l'Extension de Paramètre intégrée de bash !!

125voto

Maxime Points 3643

Nettoyez votre variable en supprimant tous les sauts de ligne :

COMMAND=$(echo $COMMAND|tr -d '\n')

108voto

Robin Green Points 12926
echo "|$COMMAND|"|tr '\n' ' '

remplacera le saut de ligne (dans POSIX/Unix ce n'est pas un retour chariot) par un espace.

Pour être honnête, je penserais à passer à quelque chose de plus rationnel que bash. Ou éviter de générer ces données malformées en premier lieu.

Hmmm, cela semble également être une faille de sécurité horrible, en fonction de l'origine des données.

15voto

wjordan Points 11

En utilisant bash:

echo "|${COMMAND/$'\n'}|"

(Notez que le caractère de contrôle dans cette question est un 'saut de ligne' (\n), et non un retour chariot (\r); ce dernier aurait affiché REBOOT| sur une seule ligne.)

Explication

Utilise l'expansion des paramètres de la coquille Bash (${parameter/pattern/string}):

Le pattern est développé pour produire un motif exactement comme dans le cas de l'expansion des noms de fichiers. Paramètre est développé et la correspondance la plus longue de pattern parmi sa valeur est remplacée par string. [...] Si string est nul, les correspondances de pattern sont supprimées et le / suivant pattern peut être omis.

Utilise également la construction de citation $'' ANSI-C pour spécifier un saut de ligne en tant que $'\n'. Utiliser directement un saut de ligne fonctionnerait également, bien que moins élégant :

echo "|${COMMAND/
}|"

Exemple complet

#!/bin/bash
COMMAND="$'\n'REBOOT"
echo "|${COMMAND/$'\n'}|"
# Résultat |REBOOT|

Ou, en utilisant des sauts de ligne :

#!/bin/bash
COMMAND="
REBOOT"
echo "|${COMMAND/
}|"
# Résultat |REBOOT|

12voto

gaoithe Points 377

Ajouter une réponse pour montrer un exemple de suppression de plusieurs caractères, y compris \r en utilisant tr et en utilisant sed. Et illustration en utilisant hexdump.

Dans mon cas, j'avais constaté qu'une commande se terminant par awk print du dernier élément |awk '{print $2}' dans la ligne contenait un retour chariot \r ainsi que des guillemets.

J'ai utilisé sed 's/["\n\r]//g' pour supprimer à la fois le retour chariot et les guillemets.

J'aurais aussi pu utiliser tr -d '"\r\n'.

Il est intéressant de noter que sed -z est nécessaire si l'on souhaite supprimer les caractères de saut de ligne \n.

$ COMMANDE=$'\n"REBOOT"\r   \n'

$ echo "$COMMANDE" |hexdump -C
00000000  0a 22 52 45 42 4f 4f 54  22 0d 20 20 20 0a 0a     |."REBOOT".   ..|

$ echo "$COMMANDE" |tr -d '"\r\n' |hexdump -C
00000000  52 45 42 4f 4f 54 20 20  20                       |REBOOT   |

$ echo "$COMMANDE" |sed 's/["\n\r]//g' |hexdump -C
00000000  0a 52 45 42 4f 4f 54 20  20 20 0a 0a              |.REBOOT   ..|

$ echo "$COMMANDE" |sed -z 's/["\n\r]//g' |hexdump -C
00000000  52 45 42 4f 4f 54 20 20  20                       |REBOOT   |

Et ceci est pertinent: Quels sont le retour chariot, la saut de ligne et le saut de forme ?

  • CR == \r == 0x0d
  • LF == \n == 0x0a

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X