Wie kann ich BSD sed anweisen, Escape-Sequenzen wie \ n und \ t zu interpretieren?

14

Ich habe einen sed-Ersatzbefehl, der sowohl mit BSD sedals auch mit GNU kompatibel sein soll sed. Erweiterte reguläre Ausdrücke sind kein Problem, da ich sie in diesem Fall nicht benötige. Mein Hauptproblem ist der Unterschied in der Art und Weise, wie die beiden sedZeichen-Escape-Sequenzen in den Ersetzungszeichenfolgen interpretieren . Meine Ersetzungszeichenfolge enthält Tabulatoren und Zeilenumbrüche, und ich möchte, dass sie zur Vereinfachung der Wartung in den Befehlszeichenfolgen angezeigt werden. BSD sedinterpretiert die Escape-Sequenzen jedoch nicht und GNU sed tut dies . Was ist der geeignete Weg, sedum diese Escape-Sequenzen auf BSD zu interpretieren? Die folgenden zwei Ausschnitte stehen für mein Problem:

GNU sed

echo ABC | sed 's/B/\n\tB\n'

yeilds

A
    B
C

BSD sed

echo ABC | sed 's/B\n\tB\n'

Ausbeuten

AntBnC

Offensichtlich \nund \tsind nicht als Escape - Sequenzen von BSD interpretiertsed

Nun zu meiner Frage. Laut der BSD- sedManpage:

Um ein Newline-Zeichen in der Ersetzungszeichenfolge anzugeben, müssen Sie diesem einen Backslash voranstellen.

Bedeutet dies, dass ich einem wörtlichen Zeilenumbruch einen Backslash voranstellen muss? Wie kann man anweisen sed, Escape-Sequenzen wie \nim Ersetzungstext zu interpretieren ?

Ephsmith
quelle
2
BSD sed ist kein GNU sed, und ich glaube nicht, dass es solche Fluchten in der Ausgabe unterstützt. Sie müssen entweder wörtliche Zeichen einfügen, GNU sed installieren oder zu etwas wechseln, das solche Fluchten wie awk unterstützt.
JW013
@jw013, mir ist klar, was die Unterscheidung zwischen den beiden betrifft. Die Installation von GNU sed ist keine Option. Ich hatte gehofft, genug Gemeinsamkeiten zwischen den beiden zu finden, um das zu erreichen, wonach ich strebe sed. Am Ende wird es wahrscheinlich Sinn machen, awk zu verwenden. Was halten Sie von der Interpretation der von mir zitierten BSD sed-Manpage?
Ephsmith
2
Ja, Sie müssen wörtliche Tabulatoren und Zeilenumbrüche verwenden, und bei Zeilenumbrüchen müssen Sie ihnen einen Backslash voranstellen, bei dem es sich im Grunde nur um einen Zeilenfortsetzungsmechanismus handelt.
JW013
@jw013, danke für deine tollen Antworten. Zu diesem Zeitpunkt werde ich mich aus Gründen der Wartung an Ihren Rat halten und meine Lösung in awk überarbeiten.
Ephsmith
Gute Wahl - awk ist ein viel besserer Plan als die derzeit akzeptierte Antwort :)
jw013

Antworten:

6

Wenn Sie portable Skripte schreiben müssen, sollten Sie sich an die Funktionen des POSIX-Standards halten (auch bekannt als Single Unix oder Open Group Base Specification). Die Ausgabe 7 (auch bekannt als POSIX-1.2008) ist die neueste, aber viele Systeme haben sie noch nicht vollständig übernommen. Ausgabe 6, auch bekannt als POSIX-1.2001, wird im Großen und Ganzen von allen modernen Unices zur Verfügung gestellt.

In sed , die Bedeutung von Escape - Sequenzen wie \tund \nist nicht tragbar, mit der Ausnahme , dass in einem regulären Ausdruck , \nfür eine neue Zeile steht. Ist im Ersetzungstext für einen sBefehl \nnicht portierbar, aber Sie können die Sequenz Backslash-Newline verwenden, um für eine Newline zu stehen.

Eine tragbare Methode zum Generieren eines Tabulatorzeichens (oder eines anderen in Oktal ausgedrückten Zeichens) ist mit tr. Speichern Sie das Zeichen in einer Shell-Variablen und ersetzen Sie diese Variable im sed-Snippet.

tab=$(echo | tr '\n' '\t')
escape=$(echo | tr '\n' '\033')
embolden () {
  sed -e 's/^/'"$escape"'[1m/' -e 's/$/'"$escape"'[0m/'
}

Beachten Sie erneut, dass Zeilenumbrüche in regulären Ausdrücken und in sErsetzungstexten unterschiedlich ausgedrückt werden müssen .

Vielleicht möchten Sie stattdessen awk verwenden. Es erlaubt Backslash-Escapes, einschließlich Oktal-Escapes \ooo, in jedem String-Literal.

Gilles 'SO - hör auf böse zu sein'
quelle
7

Sie können die Bash- $'...'Anführungszeichen verwenden, um die Escape- Zeichen zu interpretieren, bevor Sie den String an übergeben sed.

Von der Bash-Manpage:

   Words  of  the  form  $'string'  are  treated specially.  The word
   expands to string, with backslash-escaped characters  replaced  as
   specified  by the ANSI C standard.  Backslash escape sequences, if
   present, are decoded as follows:
          \a     alert (bell)
          \b     backspace
          \e     an escape character
          \f     form feed
          \n     new line
          \r     carriage return
          \t     horizontal tab
          \v     vertical tab
          \\     backslash
          \'     single quote
          \nnn   the eight-bit character whose  value  is  the  octal
                 value nnn (one to three digits)
          \xHH   the eight-bit character whose value is the hexadeci-
                 mal value HH (one or two hex digits)
          \cx    a control-x character

   The expanded result is single-quoted, as if the  dollar  sign  had
   not been present.

   A  double-quoted  string  preceded by a dollar sign ($) will cause
   the string to be translated according to the current  locale.   If
   the  current locale is C or POSIX, the dollar sign is ignored.  If
   the string is translated and replaced, the replacement is  double-
   quoted.
Kevin
quelle
3

Dies wurde auf Stack Overflow beantwortet:

/programming/1421478/how-do-i-use-a-new-line-replacement-in-a-bsd-sed

Es ist ziemlich genau das, was jw013 gesagt hat.

Um einen wörtlichen Tabulator einzufügen, geben Sie ctrl+ ein VTab.

Bahamat
quelle
danke für den hinweis. Ich hasse , dass meine Google - Suchen nicht zurückgekommen , dass Link: D
ephsmith
1
Der Vorschlag für die Registerkarte Strg-V ist schalenabhängig, z. B. funktioniert er bei Fischen nicht.
anddam
Da ich noch nie Fisch gegessen hatte, wusste ich es nicht, aber es war gut zu wissen.
Bahamat