Comment supprimer une nouvelle ligne d'une chaîne dans Bash

110

J'ai la variable suivante.

echo "|$COMMAND|"

qui retourne

|
REBOOT|

Comment puis-je supprimer cette première nouvelle ligne?

Matt Leyland
la source
7
Pourquoi est-ce marqué comme dupe? Cette question concerne la suppression d'un retour chariot. La question en double présumée à laquelle elle renvoie concerne la suppression des espaces et ne mentionne qu'incidemment les retours chariot.
Michael Scheper
1
@MichaelScheper a accepté et a rouvert.
fedorqui 'SO arrêtez de nuire' le
La terminologie ici est étrange. Le caractère de fin de ligne Unix \n(hex 0x0A) est appelé lie feed (LF); il est distinct du retour chariot de caractères (CR) \r(hex 0x0D) qui est utilisé sous Windows et dans de nombreux protocoles réseau comme premier octet dans la séquence de fin de ligne de deux octets CR LF.
tripleee

Réponses:

114

Sous , il y a quelques bashismes:

La trcommande pourrait être remplacée par // bashism :

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

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

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

Voir Extension des paramètres et QUOTING dans la page de manuel de bash:

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

man -Pless\ +/^\\\ *Parameter\\\ Exp bash
man -Pless\ +/^\\\ *QUOTING bash

Plus loin...

Comme demandé par @AlexJordan, cela supprimera tous les caractères spécifiés. Alors que $COMMANDfaire si contiennent des espaces ...

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

CLEANED=${COMMAND//[$'\t\r\n']}
echo "|$CLEANED|"
|                 RE BOOT                 |

shopt -q extglob || { echo "Set shell option 'extglob' on.";shopt -s extglob;}

CLEANED=${CLEANED%%*( )}
echo "|$CLEANED|"
|                 RE BOOT|

CLEANED=${CLEANED##*( )}
echo "|$CLEANED|"
|RE BOOT|

Prochainement:

COMMAND=$'         \n        RE BOOT      \r           \n'
CLEANED=${COMMAND//[$'\t\r\n']} && CLEANED=${CLEANED%%*( )}
echo "|${CLEANED##*( )}|"
|RE BOOT|

Remarque: ont l' extgloboption d'être activé ( shopt -s extglob) afin d'utiliser la *(...)syntaxe.

F. Hauri
la source
1
C'est la manière de supprimer les sauts de ligne d'une variable dans BASH. D'autres réponses invoquent inutilement un processus TR supplémentaire. BTW, il a l'avantage supplémentaire de supprimer les espaces de fin!
ingyhere
1
Notez qu'il supprime également les espaces internes d'une chaîne ... COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n ']}|"retourne|REBOOT|
Alex Jordan
2
@AlexJordan Oui, c'est une fonctionnalité recherchée : vous pouvez fouetter l'espace après \npour éviter cela: COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n']}|"reviendra |RE BOOT|.
F.Hauri
2
Comment fonctionne le modèle ${COMMAND//[$'\t\r\n']}? Je pensais que ${COMMAND//[\t\r\n]}cela fonctionnerait simplement, mais ce n'est pas le cas. À quoi sert le $symbole et les guillemets simples aussi?
haridsv
1
En ce qui concerne la syntaxe $ '', c'est la citation ANSI C (mentionnée dans la réponse wjordans).
chuckx
81
echo "|$COMMAND|"|tr '\n' ' '

remplacera la nouvelle ligne (dans POSIX / Unix ce n'est pas un retour chariot) par un espace.

Pour être honnête, je penserais à passer de bash à quelque chose de plus sain d'esprit. Ou en évitant de générer ces données mal formées en premier lieu.

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

Robin Green
la source
La date provient d'une requête curl qui se trouve sur le même serveur, comment pourrais-je procéder pour la mettre dans une nouvelle var? newvar = $ (echo "| $ COMMAND |" | tr '\ n' '')
Matt Leyland
2
Oui. Mais s'il vous plaît dites-moi que vous n'autorisez pas des personnes arbitraires à redémarrer votre serveur à distance sans mot de passe ...
Robin Green
31
Pourquoi n'avez-vous pas utilisé tr -d '\n'pour déposer au lieu de remplacer par un espace
F.Hauri
3
Veuillez fouetter les tuyaux inutiles! Utiliser à la tr '\n' ' ' <<< "|$COMMAND|"place deecho ... | ...
F.Hauri
12
@ F.Hauri: ou trs inutiles:"|${COMMAND//$'\n'}|"
rici
75

Nettoyez votre variable en supprimant tous les retours chariot:

COMMAND=$(echo $COMMAND|tr -d '\n')
Maxime Chéramy
la source
22
Est-ce que cette bande ne saute pas de ligne? Ne devrait-il pas l'être à la tr -d '\r'place?
Izzy
3
Faire écho à une variable non commentée supprime tous les caractères IFS (nouvelle ligne, espace, tabulation par défaut). Donc, si vous comptez faire cela, sachez que tous les caractères IFS sont supprimés et que vous n'avez pas besoin du fichier tr. Donnera simplement COMMAND=$(echo $COMMAND)un effet similaire. Ce qui est, vraisemblablement, l'apparition du diable car il invoque un nouveau processus, mais c'est quand même assez court et doux pour les yeux de l'homme et si vous avez une seconde ou deux à perdre dans votre vie, vous voudrez peut-être prendre le coup :-).
Mike S
J'ai mis à jour la question pour dire "saut de ligne", car son exemple a montré qu'il s'agissait d'un saut de ligne, pas d'un retour chariot. Cette réponse est toujours correcte, mais devrait peut-être être mise à jour pour dire "saut de ligne" au lieu de "retour chariot"?
Benjamin W.
8

Utilisation bash:

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

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

Explication

Utilise l' extension des paramètres du shell Bash ${parameter/pattern/string}:

Le modèle est développé pour produire un modèle comme dans l'expansion du nom de fichier. Le paramètre est développé et la plus longue correspondance du modèle par rapport à sa valeur est remplacée par une chaîne . [...] Si la chaîne est nulle, les correspondances de modèle sont supprimées et le modèle / suivant peut être omis.

Utilise également la construction de $'' guillemets ANSI-C pour spécifier une nouvelle ligne comme $'\n'. Utiliser une nouvelle ligne directement fonctionnerait également, bien que moins joli:

echo "|${COMMAND/
}|"

Exemple complet

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

Ou, en utilisant des nouvelles lignes:

#!/bin/bash
COMMAND="
REBOOT"
echo "|${COMMAND/
}|"
# Outputs |REBOOT|
Wjordan
la source
6

Ce qui a fonctionné pour moi était echo $testVar | tr "\n" " "

Où testVar contenait ma variable / sortie de script

Prachi
la source
4

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

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

J'avais l'habitude sed 's/["\n\r]//g'de supprimer à la fois le retour chariot et les guillemets.

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

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

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

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

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

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

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

Et ceci est pertinent: que sont le retour chariot, le saut de ligne et le saut de page?

  • CR == \ r == 0x0d
  • LF == \ n == 0x0a
Gaoithe
la source
3

Vous pouvez simplement utiliser echo -n "|$COMMAND|".

Paulo
la source
2

Si vous utilisez bash avec l'option extglob activée, vous pouvez supprimer uniquement l'espace blanc de fin via:

shopt -s extglob
COMMAND=$'\nRE BOOT\r   \n'
echo "|${COMMAND%%*([$'\t\r\n '])}|"

Cela produit:

|
RE BOOT|

Ou remplacez %% par ## pour ne remplacer que le premier espace blanc.

zeroimpl
la source
1
Cela a fonctionné comme un charme avec une sortie étrange que j'ai obtenue d'une commande docker. Merci beaucoup!
develCuy