Fügen Sie Text aus der Datei inline ein, nachdem Sie das Muster in einer anderen Datei abgeglichen haben

8

Ich versuche, den Inhalt einer Datei mit sed nach einem passenden Muster in eine andere Datei einzufügen. Meine Frage ist dieser Frage sehr ähnlich , aber ich möchte den Inhalt einer Datei inline und nicht in eine neue Zeile einfügen. Wie kann ich das machen?

Anhand der Beispielfrage, auf die ich verwiesen habe, macht die erste Antwort genau das, was ich will. Ich möchte jedoch, dass das Einfügen inline erfolgt:

sed '/First/r file1.txt' infile.txt 

Die tatsächlichen Daten, die ich einfügen möchte, sind eine JSON-Datei:

[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]
Schildkröte
quelle
Ich denke, das beantwortet Ihre Frage. Würdest du es dir ansehen und es mich wissen lassen?
Mikeserv
@mikeserv Danke für die Hilfe. Ich würde gerne Ihre Lösung ausprobieren, aber nachdem ich Ihre Lösung gelesen habe, bin ich mir nicht sicher, wie ich Ihre Vorschläge umsetzen soll. Können Sie ein Beispiel posten?
Schildkröte
Ich denke definitiv darüber nach - es sieht einfach aus - aber ich weiß nicht, wo ich anfangen soll ... OOps. Das Muster ist First- duh. Es tut uns leid.
Mikeserv
Warten Sie - Sie möchten die JSON-Newline kostenlos einfügen - wie die Newlines aus der eingefügten Datei entfernen, während sie eingefügt wird? Ich kann das mit GNU machen, sedaber ich will nur sicher gehen ...
mikeserv
Der tatsächliche JSON muss nicht geändert werden. Ich möchte den JSON nach dem Muster einfügen, damit zwischen dem Muster und dem Start des JSON keine neue Zeile steht.
Schildkröte

Antworten:

6

In Ihrer verknüpften Frage gibt es bereits eine gute awkAntwort. Ändern Sie sie einfach ein wenig, indem Sie den Inhalt verwenden, printfanstatt ihn printohne Zeilenumbruch einzufügen:

awk '/First/ { printf $0; getline < "File1.txt" }1' infile.txt

Ergebnis:

Some Text here
FirstThis is text to be inserted into the File.
Second
Some Text here

Möglicherweise möchten Sie nach "First" mit "Leerzeichen" oder ein anderes Delimeter hinzufügen printf $0 " "; ...


Wenn die eingefügte Datei viele Zeilen enthält, gilt Folgendes:

awk '/First/{printf $0; while(getline line<"File1.txt"){print line};next}1' infile.txt

Ergebnis:

Some Text here
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]
Second
Some Text here
jimmij
quelle
In meinem tatsächlichen Anwendungsfall füge ich eine große JSON-Datei ein und dieses awk-Beispiel funktioniert nicht. Ich bekomme nur eine einzelne linke Klammer, [die nach dem Mustervergleich eingefügt wird. Normaler Text funktioniert gut, aber nicht JSON?
Schildkröte
Es wurde eine Beispiel-JSON-Datendatei hinzugefügt, die für mich nicht korrekt eingefügt wird.
Schildkröte
@ Schildkröte das vielleicht weil getlinein einer Zeile liest. Verwenden Sie eine Schleife um getline: unix.stackexchange.com/a/32911/70524
muru
Ok, das hat funktioniert, aber der JSON wird jetzt VOR dem Muster eingefügt:awk '/First/ { while(getline line<"File1.txt"){print line} }1' infile.txt
Turtle
@ Schildkröte versuchen awk '/First/ { print; while(getline line<"File1.txt"){print line} }' infile.txtstattdessen.
Muru
6

Sie könnten verwenden perl(den Dateiinhalt abrufen und patterndurch pattern+ ersetzen file content):

perl -pe '$text=`cat insert.txt`; chomp($text); s/PAT/$&$text/' file.txt

hinzufügen -i, um an Ort und Stelle zu bearbeiten; gnach jedem Auftreten von PAT (Muster) anhängen, z.

perl -i -pe '$text=`cat insert.txt`; chomp($text); s/PAT/$&$text/g' file.txt

Ein anderer Weg, mit ed:

printf '%s\n' /PAT/s/PAT/\&\\ \/ - kb ". r insert.txt" j \'b j ,p q | ed -s file.txt

Zum Bearbeiten an Ort und Stelle ersetzen ,pdurch w:

 printf '%s\n' /PAT/s/PAT/\&\\ \/ - kb ". r insert.txt" j \'b j w q | ed -s file.txt

Wahrscheinlich interessiert sich niemand dafür, wie das funktioniert, aber er printfübergibt trotzdem eine Liste von Befehlen an ed:

/PAT/s/PAT/&\             #   set address to first line matching PAT and
/                         #   split the line right after PAT
-                         #   set address one line before (return to the line matching PAT)
kb                        #   mark the current line
. r insert.txt            #   insert content of insert.txt after this line         
j                         #   join current line and the next
'b                        #   set  address to marked line (return to the line matching PAT)
j                         #   join current line and the next one
,p                        #   print file content
q                         #   quit editor

Oder ohne Verwendung von printfund |:

ed -s file.txt <<< $'/PAT/s/PAT/&\\\n/\n-\nkb\n. r insert.txt\nj\n\'b\nj\nw\nq\n'
don_crissti
quelle
Ich habe einmal 8 Stunden lang tief in den exDokumenten gearbeitet - ich mag das viKonsolenfenster, das Sie machen können. Eine einzelne Linie oder eine einstellbare Größe oder ... na ja, wahrscheinlich viele Sachen, von denen ich einfach nie den Dreh raus hatte. Wie auch immer, ich möchte es wirklich herausfinden - ich habe nur über die POSIX-Dokumente nachgedacht. Hast du irgendwelche Empfehlungen?
Mikesserv
Nicht viele Ressourcen (die ich leider kenne), die ed... die POSIX-Dokumente abdecken , es gibt auch diese Seite ... Ich empfehle, das Tool für einfache Aufgaben / Experimente zu verwenden (zumindest habe ich so gelernt, nur die zu lesen docs, Kernighans kurzes Intro und Krummins ' Spickzettel ). Mit Ihrem Wissen über sedsollten Sie keine Probleme haben. Es sei denn, Ihre Frage exex
betrifft
es geht darum ex- was ist, wie ich es verstehe, nur eine edErweiterung? Eine Sache, die mich beim Spielen umgehauen hat, war der tmp-Speicher - ich habe versucht, eine große Datei zu laden und musste darauf warten. Auf der anderen Seite finde ich die unzähligen Puffer attraktiv - ich war einfach nicht gut genug, um sie effizient aufzuteilen. danke für die links.
Mikeserv
5

So wäre es ein wenig schwierig sein , diese Arbeit portably in machen sed- Sie suchen sollen cutund / oder pastemit einigen regex Vorläufern zu erzeugen sie Skript in diesem Zusammenhang - und das liegt daran , sedwird immer Einsatz einer \newline vor dem Ausgang eines read. Trotzdem mit GNU sed:

sed '/First/{x;s/.*/cat file/e;H;x;s/\n//}' <<\IN 
First
Second
Third
IN

eDies funktioniert, indem catjedes Mal ausgeführt wird, wenn Ihre /First/Adresse gefunden wird. Dies geschieht im halten Raum (eine Art - ohnehin ein alternativer Puffer - weil ich sie xändere, geschieht dies tatsächlich im Musterraum, der früher halter Raum war) , um den Inhalt der FirstZeilenübereinstimmung beizubehalten und dann catdie Ausgabe anzuhängen zu Ihrer Linie und entfernt die dazwischenliegende \newline.

AUSGABE:

First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]
Second
Third

Wenn Sie nun möchten, dass der gesamte Inhalt der Datei zwischen zwei Teile einer Zeile passt , die etwas anders funktionieren müssen, entferne ich mit dem obigen Befehl einfach die nachfolgende neue Zeile zwischen dem Ende der übereinstimmenden Zeile und dem Anfang der Datei. Trotzdem können Sie dies auch tun:

sed '/First/{s//&\n/;h
         s/.*/{ cat file; echo .; }/e;G
         s/\(.*\).\n\(.*\)\n/\2\1/
}' <<\IN
Third
Second
First Second Third
Third
Second
First Second Third
IN

\nDadurch wird die Zeile bei der Übereinstimmung mit einem Ewline-Zeichen geteilt, im halten Leerzeichen egespeichert , xecutes cat- das den Musterraum durch seine Ausgabe ersetzt - Gder Inhalt des Haltebereichs, der nach einem anderen \nEwline-Zeichen an unseren neuen Musterraum angehängt wird, wird neu angeordnet und dann neu angeordnet \newline Trennzeichen.

Ich möchte echo .alle nachgestellten \nEwline-Zeichen beibehalten file- aber wenn dies nicht Ihr Wunsch ist (und für Ihr Beispiel sowieso nicht sehr relevant ist) , können Sie darauf verzichten und die ersten .zuvor .\nin der folgenden s///Substitution entfernen.

Kurz bevor der Musterbereich neu angeordnet wird, sieht er folgendermaßen aus:

^cat's output - any number of newlines.*.\nmatch on First\nrest of match$

AUSGABE:

Third
Second
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
] Second Third 
Third
Second
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
] Second Third
mikeserv
quelle
1
Das ist eine großartige Antwort, Mike.
don_crissti
@don_crissti - vielen Dank. Die s///eSyntax ist ziemlich cool - Sie können alles damit machen, was Sie an einer Eingabeaufforderung tun könnten. Tatsächlich ist es auch ein ziemlich praktischer Eingabeaufforderungsprozessor. Ich habe damit experimentiert und einige einfachere Shells, die nicht viel für die Linienbearbeitung bieten und beeindruckt sind. Wenn Sie es jedoch verwenden, denken Sie daran, dass Sie dabei den gesamten Musterbereich entfernen. Das Ersetzen nur eines Teils beliebiger Daten und das anschließende eAusführen der Ergebnisse kann katastrophal sein. Ich weiß - ich war dort.
Mikesserv