Warum zeigt "echo -e" \\\ SOME_TEXT "nur einen Backslash?

19

Könnte jemand erklären, was sich hinter den Kulissen von Charakteren abspielt, die in der Linux-Shell entkommen? Ich habe Folgendes ausprobiert und viel gegoogelt, ohne Erfolg zu haben, was (und wie) vor sich geht:

root@sv01:~# echo -e "\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\\\ Hello!"
\\\ Hello!
root@sv01:~# echo -e "\n Hello!"

 Hello!
root@sv01:~# echo -e "\\n Hello!"

 Hello!
root@sv01:~# echo -e "\\\n Hello!"
\n Hello!

Ich bin dort total verloren. Warum geben beispielsweise drei Backslashes nur einen Backslash? Ich würde erwarten: die ersten beiden werden zu einem geflüchtet, der dritte wird nichts zu fliehen finden, so dass es ein Schrägstrich bleibt (Zeile im ersten Experiment), aber was passiert ist, dass die dritte gerade verschwindet.
Warum bekomme ich einen Backslash von vier \\\\ Hello? Ich würde erwarten, dass jedes Paar einen Backslash gibt -> zwei Backslashes.

Und warum brauche ich im letzten Fall drei Backslashes, um \ n zu entkommen? Was passiert im Hintergrund der Flucht, um das zu bekommen? und wie unterscheidet es sich von \\ncase?

Ich freue mich über jede Erklärung, was in den vorherigen Zeilen vor sich geht.

Mohammed Noureldin
quelle
echo -eVerhalten ist sowieso nicht standarddefiniert - siehe pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html . Die Ausgabe ist vollständig implementierungsdefiniert, wenn die Eingaben einen wörtlichen Backslash enthalten. Die einzige zulässige Option ist -n(dh, für eine standardkonforme Implementierung wird die Ausgabe echo -egedruckt -e).
Charles Duffy
... auch wenn Sie 100% sicher sind , dass die Shell bash ist, selbst dann echo -e ist nicht sicher: echowird in Übereinstimmung mit dem Standard verhalten , wenn beide posixund xpg_echoRuntime - Optionen aktiviert sind, oder wenn mit dem entsprechenden Aufbauzeitmöglichkeiten zusammengestellt. Die sichere Vorgehensweise ist, printfstattdessen zu verwenden - siehe die Abschnitte APPLICATION USAGE und RATIONALE des obigen Links, in denen beschrieben wird, wie Sie printfals Ersatz für agieren können echo.
Charles Duffy

Antworten:

28

Dies liegt daran bashund echo -ekombiniert. Vonman 1 bash

Ein Backslash ( \) ohne Anführungszeichen ist das Escape-Zeichen. Es behält den Literalwert des nächsten folgenden Zeichens bei, mit Ausnahme von <newline>. […]

Zeichen in doppelten Anführungszeichen bewahrt den wörtlichen Wert aller Zeichen innerhalb der Anführungszeichen, mit Ausnahme von umschließenden $, `, \[...] Der Backslash nur seine besondere Bedeutung behält , wenn sie durch eine der folgenden Zeichen folgen: $,`, ", \, oder <newline>.

Der Punkt ist: Backslash in doppelten Anführungszeichen ist nicht immer etwas Besonderes.

Es gibt verschiedene Implementierungen von echoim Allgemeinen, es ist ein eingebautes bash; Das Wichtigste hier ist dieses Verhalten:

Ist dies der -eFall, werden die folgenden Sequenzen erkannt:
\\
Backslash
[…]
\n
Neue Zeile

Jetzt können wir dekodieren:

  1. echo -e "\ Hello!"- nichts Besonderes für bash, nichts Besonderes für echo; \bleibt.
  2. echo -e "\\ Hello!"- die erste \sagt bash, die zweite \wörtlich zu behandeln ; echobekommt \ Hello!und verhält sich wie oben.
  3. echo -e "\\\ Hello!"- die erste \sagt bash, die zweite \wörtlich zu behandeln ; echobekommt \\ Hello!und (wegen -e) erkennt es \\als \.
  4. echo -e "\\\\ Hello!"- die erste \sagt bash, die zweite \wörtlich zu behandeln ; der dritte sagt dasselbe über den vierten; echobekommt \\ Hello!und (wegen -e) erkennt es \\als \.
  5. echo -e "\\\\\ Hello!"- die erste \sagt bash, die zweite \wörtlich zu behandeln ; der dritte sagt dasselbe über den vierten; der letzte ist nicht besonders; echobekommt \\\ Hello!und (wegen -e) erkennt es den Anfangsbuchstaben \\als \, der letzte \bleibt erhalten.

Und so weiter. Wie Sie sehen können, führen bis zu vier aufeinanderfolgende Backslashes zu einem Ergebnis. Deshalb braucht man (mindestens) neun, um drei zu bekommen. 9 = 4 + 4 + 1.

Jetzt mit \n:

  1. echo -e "\n Hello!"- Es gibt nichts Besonderes bash, Echo bekommt den gleichen String und wird (wegen -e) \nals Newline interpretiert .
  2. echo -e "\\n Hello!"- bashinterpretiert \\als \; echowird \n Hello!und das Ergebnis ist das gleiche wie oben.
  3. echo -e "\\\n Hello!"- bashinterpretiert die Initiale \\als \; echowird \\n Hello!und (wegen -e) wird es \\als Literal interpretiert \, das gedruckt werden muss.

Die Ergebnisse wären unterschiedlich mit 'statt "(aufgrund unterschiedlichen bashVerhaltens) oder ohne -e(unterschiedliches echoVerhalten).

Kamil Maciorowski
quelle
1
Vielen Dank! Es gibt also zwei Escape-Schritte, den von bash ausgeführten und den zweiten, der -eden bereits von bash ausgeführten Text beurteilt. Ist das richtig? Wenn dies korrekt ist, wird die Verwirrung beseitigt. Könnten Sie vielleicht erwähnen, wie sich das sedverhält? Hat es eine eigene Fluchttechnik? Ich meine, verhält es sich wie ein Echo -e?
Mohammed Noureldin
2
@ MohammedNoureldin Ja, es gibt zwei Schritte. Ihre ursprüngliche Frage ist in Ordnung, machen wir sie nicht zu kompliziert sed. Sie können aber auch eine andere Frage stellen (ungefähr sed), machen Sie zuerst Ihre eigenen Nachforschungen.
Kamil Maciorowski
3
@MohammedNoureldin sedfolgt den gleichen Grundprinzipien: bash interpretiert die Befehlszeile gemäß ihren Regeln und analysiert (und entfernt möglicherweise) Anführungszeichen und Escapezeichen. Das Ergebnis davon wird an übergeben sed, der es gemäß seiner Escape-Regeln interpretiert . Übrigens können Sie dies vereinfachen, indem Sie eine Zeichenfolge in bashAnführungszeichen eingeben, da für diese keine Escape-Interpretation (durch Bash) ausgeführt wird. Bash entfernt die einfachen Anführungszeichen und übergibt die darin enthaltenen Informationen direkt an den Befehl.
Gordon Davisson
Ich habe noch ein kleines Problem für den echo -e "\\\n Hello!"Fall. Hier wird bash fliehen, und es wird werden \\n, dann -ewerden die resultierenden zwei Backslashes fliehen \\nund dann werden sie \n. Wer interpretiert \nes nun, um eine neue Zeile zu machen? Normalerweise echo -e "\n Hello!"tut bash im Falle von nichts und -einterpretiert \nals neue Zeile. Aber in der erstgenannten Situation wurde der Interpretationsprozess durchgeführt, bevor \nman interpretiert wurde. Könnten Sie das bitte erklären?
Mohammed Noureldin
1
Ok, meine Schuld, ich habe darüber 2 Tage lang mit ihren Nächten gelesen, daher habe ich anscheinend angefangen, die Fälle zu mischen. Ich glaube, ich habe noch etwas anderes, sedwas mich letzte Nacht verwirrt hat (vielleicht habe ich gestern etwas falsch gemacht), aber jetzt habe ich habe das gleiche mit echo -eund nochmal probiert sedund habe das selbe bekommen wie mit ausnahme, danke!
Mohammed Noureldin