So entfernen Sie eine neue Zeile aus einer Zeichenfolge in Bash

110

Ich habe die folgende Variable.

echo "|$COMMAND|"

was zurückkehrt

|
REBOOT|

Wie kann ich diesen ersten Zeilenumbruch entfernen?

Matt Leyland
quelle
7
Warum ist dies als Betrug markiert? Bei dieser Frage geht es um das Entfernen eines Wagenrücklaufs. Die angebliche doppelte Frage, auf die verwiesen wird, betrifft das Entfernen von Leerzeichen und erwähnt nur beiläufig Wagenrückläufe.
Michael Scheper
1
@ MichaelScheper stimmte zu und öffnete wieder.
Fedorqui 'SO hör auf zu schaden'
Die Terminologie hier ist seltsam. Das Unix- \nZeilenabschlusszeichen (hex 0x0A) wird als Lügenvorschub (LF) bezeichnet. Es unterscheidet sich vom CR \r( Character Carriage Return) (hex 0x0D), der unter Windows und in vielen Netzwerkprotokollen als erstes Byte in der Zwei-Byte-Zeilenendsequenz CR LF verwendet wird.
Tripleee

Antworten:

114

Unter gibt es einige Bashismen:

Der trBefehl könnte durch // Bashismus ersetzt werden :

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

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

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

Siehe Parametererweiterung und QUOTING in der Manpage von bash:

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

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

Des Weiteren...

Auf Anfrage von @AlexJordan werden dadurch alle angegebenen Zeichen unterdrückt . Was ist, wenn $COMMANDLeerzeichen enthalten sind?

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|

In Kürze:

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

Hinweis: hat extglobOption wird (aktiviert shopt -s extglob) zu verwenden , um *(...)Syntax.

F. Hauri
quelle
1
Auf diese Weise können Zeilenvorschübe von einer Variablen in BASH entfernt werden. Andere Antworten rufen unnötigerweise einen zusätzlichen TR-Prozess auf. Übrigens hat es den zusätzlichen Vorteil, Endräume zu entfernen!
Ingyhere
1
Beachten Sie, dass es auch interne Leerzeichen aus einer Zeichenfolge entfernt ... COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n ']}|"kehrt zurück|REBOOT|
Alex Jordan
2
@AlexJordan Ja, es ist eine gewünschte Funktion : Sie können das Leerzeichen nachher löschen \n, um dies zu verhindern: COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n']}|"wird zurückkehren |RE BOOT|.
F. Hauri
2
Wie funktioniert das Muster ${COMMAND//[$'\t\r\n']}? Ich dachte, es ${COMMAND//[\t\r\n]}würde einfach funktionieren, aber das tat es nicht. Wofür ist das $Symbol und auch die einfachen Anführungszeichen?
Haridsv
1
In Bezug auf die $ '' - Syntax ist dies ANSI C-Zitat (in der Antwort von wjordans erwähnt).
Chuckx
81
echo "|$COMMAND|"|tr '\n' ' '

ersetzt die neue Zeile (in POSIX / Unix ist es kein Wagenrücklauf) durch ein Leerzeichen.

Um ehrlich zu sein, würde ich darüber nachdenken, von Bash zu etwas Vernünftigerem zu wechseln. Oder vermeiden Sie es, diese fehlerhaften Daten überhaupt zu generieren.

Hmmm, dies scheint auch eine schreckliche Sicherheitslücke zu sein, je nachdem, woher die Daten stammen.

Robin Green
quelle
Das Datum stammt von einer Curl-Anfrage, die sich auf demselben Server befindet. Wie würde ich das in eine neue Variable einfügen? newvar = $ (echo "| $ COMMAND |" | tr '\ n' '')
Matt Leyland
2
Ja. Aber bitte sagen Sie mir, dass Sie nicht
Robin Green
31
Warum haben Sie nicht verwendet, tr -d '\n'um zu fallen, anstatt durch ein Leerzeichen zu ersetzen
F. Hauri
3
Bitte peitschen Sie nutzlose Rohre! Verwenden Sie tr '\n' ' ' <<< "|$COMMAND|"anstelle vonecho ... | ...
F. Hauri
12
@ F.Hauri: oder nutzlose tr's:"|${COMMAND//$'\n'}|"
Rici
75

Bereinigen Sie Ihre Variable, indem Sie alle Wagenrückläufe entfernen:

COMMAND=$(echo $COMMAND|tr -d '\n')
Maxime Chéramy
quelle
22
Streift das nicht Linefeeds? Sollte es nicht tr -d '\r'stattdessen sein?
Izzy
3
Durch das Echo einer nicht kommentierten Variablen werden alle IFS-Zeichen entfernt (Zeilenumbruch, Leerzeichen, Tabulator standardmäßig). Wenn Sie dies tun, sollten Sie sich darüber im Klaren sein, dass alle IFS-Zeichen gelöscht werden und Sie das nicht benötigen tr. Einfach COMMAND=$(echo $COMMAND)wird ein ähnlicher Effekt geben. Das ist vermutlich Teufelsbrut, da es einen neuen Prozess auslöst, aber es ist immer noch ziemlich kurz und süß für die Augen des Menschen, und wenn Sie ein oder zwei Sekunden in Ihrem Leben übrig haben, sind Sie möglicherweise bereit, den Treffer zu nehmen :-).
Mike S
Ich habe die Frage mit "Zeilenvorschub" aktualisiert, da das Beispiel gezeigt hat, dass es sich um einen Zeilenvorschub handelt, nicht um einen Wagenrücklauf. Diese Antwort ist immer noch richtig, sollte aber möglicherweise aktualisiert werden, um "Zeilenvorschub" anstelle von "Wagenrücklauf" zu sagen?
Benjamin W.
8

Verwenden von bash:

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

(Beachten Sie, dass das Steuerzeichen in dieser Frage eine 'Newline' ( \n) und kein Wagenrücklauf ( \r) ist. Letzteres würde REBOOT|in einer einzelnen Zeile ausgegeben .)

Erläuterung

Verwendet die Bash Shell-Parametererweiterung ${parameter/pattern/string} :

Das Muster wird erweitert, um ein Muster wie bei der Dateinamenerweiterung zu erzeugen. Der Parameter wird erweitert und die längste Übereinstimmung des Musters mit seinem Wert wird durch eine Zeichenfolge ersetzt . [...] Wenn Zeichenfolge null ist, Spiele von Mustern werden gelöscht und die / folgenden Muster weggelassen werden können.

Verwendet auch das $'' ANSI-C- Anführungszeichenkonstrukt, um eine neue Zeile als anzugeben $'\n'. Die direkte Verwendung eines Zeilenumbruchs würde ebenfalls funktionieren, wenn auch weniger hübsch:

echo "|${COMMAND/
}|"

Vollständiges Beispiel

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

Oder mit Zeilenumbrüchen:

#!/bin/bash
COMMAND="
REBOOT"
echo "|${COMMAND/
}|"
# Outputs |REBOOT|
wjordan
quelle
6

Was für mich funktioniert hat war echo $testVar | tr "\n" " "

Wo testVar meine Variablen- / Skriptausgabe enthielt

Prachi
quelle
4

Hinzufügen einer Antwort, um ein Beispiel für das Entfernen mehrerer Zeichen zu zeigen, einschließlich \ r mit tr und sed. Und mit Hexdump veranschaulichen.

In meinem Fall hatte ich festgestellt, dass ein Befehl, der mit awk print des letzten Elements |awk '{print $2}'in der Zeile endet, einen Wagenrücklauf sowie Anführungszeichen enthielt.

Ich habe sed 's/["\n\r]//g'sowohl den Wagenrücklauf als auch die Anführungszeichen entfernt.

Ich hätte es auch gebrauchen können tr -d '"\r\n'.

Interessant zu beachten sed -zist, wenn man \ n Zeilenvorschubzeichen entfernen möchte.

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

Und das ist relevant: Was sind Wagenrücklauf, Zeilenvorschub und Formularvorschub?

  • CR == \ r == 0x0d
  • LF == \ n == 0x0a
gaoithe
quelle
3

Sie können einfach verwenden echo -n "|$COMMAND|".

Paulo
quelle
2

Wenn Sie bash mit aktivierter extglob-Option verwenden, können Sie nur das nachfolgende Leerzeichen entfernen über:

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

Dies gibt aus:

|
RE BOOT|

Oder ersetzen Sie %% durch ##, um nur das führende Leerzeichen zu ersetzen.

zeroimpl
quelle
1
Dies funktionierte wie ein Zauber mit einer seltsamen Ausgabe, die ich von einem Docker-Befehl erhielt. Vielen Dank!
DevelCuy