Ist es portierbar, das Argument des sed-Befehls „i\“ einzurücken?

Ist es portierbar, das Argument des sed-Befehls „i\“ einzurücken?

Ich hatte den Eindruck, von derPOSIX-Spezifikationen fürseddass es notwendig ist, den Text in der Zeile nach dem Befehl linksbündig auszurichten i\, es sei denn, Sie möchten führende Leerzeichen in der Ausgabe.

Ein kurzer Test auf meinem Mac (mit BSD sed) zeigt, dass dies vielleicht der Fall istnichtnotwendig:

$ cat test.sed 
#!/bin/sed -f
i\
      This line starts with spaces.
$ echo some text | sed -f test.sed
This line starts with spaces.
some text
$ 

Ich kann dies jedoch nirgends dokumentiert finden. Es steht nicht in den POSIX-Spezifikationen und nicht einmal auf sedder Manpage meines Systems.

Kann ich mich in sedSkripten, die portierbar sein sollen, auf dieses Verhalten verlassen? Wie portabel ist es?

(Ist es dokumentiertüberall?)


(Bonusfrage: Ist es überhaupt möglich, seddas Einfügen von Leerzeichen am Anfang einer an übergebenen festen Zeile zu erzwingen i\?)

Antwort1

Nein, aber Ihr Skript ist portierbar, solange Sie führende Leerzeichen maskieren. Warum? Weil einige seds Leerzeichen aus Textzeilen entfernen und die einzige Möglichkeit, dies zu vermeiden, darin besteht, führende Leerzeichen zu maskieren, wie diese Manualpages aus dem letzten Jahrhundert erklären:1,2,3
Dasselbe gilt für BSD sed( OSXhabe den Code einfach kopiert, es ist nicht ihre Erweiterung) und wenn Sie die Archive überprüfen und diemanSeite vonBSD 2.11es ist ziemlich klar:

(1)i\
Text
.......
Ein Argument bezeichnetTextbesteht aus einer oder mehreren Zeilen, von denen alle bis auf die letzte mit enden, um '\'den Zeilenumbruch zu verbergen. Backslashes im Text werden wie Backslashes in der Ersetzungszeichenfolge eines 's' Befehls behandelt und können verwendet werden, um anfängliche Leerzeichen und Tabulatoren vor dem Entfernen zu schützen, das in jeder Skriptzeile durchgeführt wird.

Wo ist dies nun in der POSIX-Spezifikation dokumentiert? Dort steht nur

Der Argumenttext muss aus einer oder mehreren Zeilen bestehen. Jedem eingebetteten <newline> im Text muss ein <backslash> vorangestellt werden. Andere <backslash>-Zeichen im Text müssen entfernt werden und das folgende Zeichen muss wörtlich behandelt werden.

und wenn Sie nach unten scrollen unterGRUNDLAGEes sagt

Die Anforderungen für die Akzeptanz von <blank>- und <space>-Zeichen in Befehlszeilen wurden expliziter formuliert als in früheren Vorschlägen, um die historische Praxis klar zu beschreiben und Verwirrung über den Satz „Schützen Sie anfängliche Leerzeichen und Tabulatoren vor dem Entfernen, das in jeder Skriptzeile erfolgt“ zu beseitigen, der in vielen historischen Dokumentationen der Textbeschreibung des Dienstprogramms sed vorkommt. (Es ist nicht bekannt, dass alle Implementierungen <blank>-Zeichen aus Textzeilen entfernt haben, obwohl sie alle führende <blank>-Zeichen vor der Adresse in einer Befehlszeile zugelassen haben.)

Da der Teil mit"Backslashes können verwendet werden, um"war in diesem Zitat nicht enthalten, der verbleibende Satz"Anfängliche Leerzeichen schützen..."macht keinen Sinn... 1


Zusammenfassend lässt sich sagen: Einige Implementierungen haben (und tun dies immer noch) Leerzeichen aus Textzeilen entfernt. Da jedoch die POSIX-Spezifikation, der alle Implementierungen entsprechen sollten, besagt:

Andere <Backslash>-Zeichen im Text müssen entfernt werden und das folgende Zeichen muss wörtlich behandelt werden.

Wir können daraus schließen, dass die portable Möglichkeit zum Einrücken der Zeilen im einzufügenden Text darin besteht, das führende Leerzeichen in jeder dieser Zeilen zu maskieren.


1: Ich verstehe auch nicht, warum OSXdie BSDLeute den gesamten Absatz auf der Seite geändert haben man, ohne den Quellcode zu verändern – das Verhalten ist dasselbe wie zuvor, aber der Man-Abschnitt, der dieses Zeug dokumentiert, ist nicht mehr da.

Antwort2

Es ist eine OSX- sedErweiterung, kein Standardverhalten. Sie können sehendieser Link, in Funktioncompile_text:

/*
 * Compile the text following an a or i command.
 */
static char *
compile_text()
{
    int asize, size;
    char *text, *p, *op, *s;
    char lbuf[_POSIX2_LINE_MAX + 1];

    asize = 2 * _POSIX2_LINE_MAX + 1;
    text = xmalloc(asize);
    size = 0;
    while (cu_fgets(lbuf, sizeof(lbuf))) {
        op = s = text + size;
        p = lbuf;
        EATSPACE();
        for (; *p; p++) {
            if (*p == '\\')
                p++;
            *s++ = *p;
        }
        size 

Sie haben mithilfe von EATSPACEMakros Leerzeichen gefressen.

In FreeBSD , das , , fälschlicherweise als Zeilenfortsetzungszeichen sedbehandeln kann, ist das Verhalten seltsamer. In meinem FreeBSD 9.3:\aic

$ echo 1 | sed -e 'i\ 1'
": extra characters after \ at the end of i command

Aber:

$ echo 1 | sed -e 'i\
 2'
2
1

funktioniert, und es frisst auch Speicherplatz.

GNU sed, das Erbstück, sedhat dieses Problem nicht.

Antwort3

Cuonglmgab die beste Antwort, aber fürs Protokoll:GNU sedtut:

echo foo | sed 'i\
     This line starts with spaces.'

Ausgabe:

     This line starts with spaces.
foo

verwandte Informationen