Fügen Sie Text N Zeilen vor der letzten Zeile ein


7

Ich möchte eine neue Zeile in zwei Zeilen vor der letzten Zeile einfügen. Also, wenn meine Originaldatei ist:

1
2
3
4
5

Das Ergebnis sollte sein

1
2
3
New line
4
5

Antworten:


14

Verwenden von ed:

$ printf '$-1i\nNew line\n.\n,p\n' | ed -s file
1
2
3
New line
4
5

Das edBearbeitungsskript:

$-1i
New line
.
,p

Dies bewegt sich zuerst in die Zeile eine Zeile vor dem Ende ( $-1) und fügt ( i) neuen Inhalt über dieser Zeile ein. Der eingefügte Inhalt wird mit einem einzelnen Punkt beendet (es dürfen mehrere Zeilen sein). Der letzte ,pzeigt den vollständig geänderten Puffer auf dem Terminal an.

Sie können dies in eine neue Datei umleiten oder mit in die Originaldatei zurückschreiben

printf '$-1i\nNew line\n.\nw\n' | ed -s file

(das ,pwird geändert in w).

Letzteres würden Sie auch in ähnlicher Weise exfür diesen Job verwenden:

printf '$-1i\nNew line\n.\nw\n' | ex -s file

edund exsind standardmäßige zeilenorientierte Editoren (im Gegensatz zu Vollbild-Editoren), die mit Ihrem System geliefert werden sollten. Beachten Sie, dass -sdies jeweils unterschiedliche Bedeutungen hat, jedoch für beide geeignet ist, wenn Sie solche Aufgaben im Batch-Modus bearbeiten.

  • ed. "Shell und Dienstprogramme". Basisspezifikationen . IEEE 1003.1: 2017. Die offene Gruppe.
  • ex. "Shell und Dienstprogramme". Basisspezifikationen . IEEE 1003.1: 2017. Die offene Gruppe.

Weiterführende Literatur:

  • Dale Dougherty und Tim O'Reilly (1987). "Erweiterte Bearbeitung". Unix-Textverarbeitung . Hayden Bücher.

1
Dies ist die bisher beste Lösung, aber denken Sie daran, dass sie auch ihre Grenzen hat (Umgang mit großen Dateien oder Einfügen von Zeilen, die aus einem einzelnen Punkt bestehen).
don_crissti

4

Sie können auch GNU verwenden sed:

sed -zE 's/(\n[^\n]*){3}$/\nNew-line&/' infile

Fügen Sie eine Zeile New-linein die drittletzte Zeile der Datei ein (Fügen Sie eine Zeile zwei Zeilen vor der letzten Zeile ein).

Diese (\n[^\n]*){3}$Begegnungen \newline durch irgendetwas gefolgt , aber nicht ein \newline und maximal 3 mal von Ende der Datei , in der -zOption Gehäuse sed eine Datei als eine einzige Zeile (separate Leitungen von NUL - Zeichen) zu lesen. Es wird also nur unten übereinstimmen (zwischen den von mir hervorgehobenen Sternchen):

3*\n
4\n
5\n*

Portabilität würden Sie verwenden:

sed -e ':t;N;$!bt; s/\(\n[^\n]*\)\{2\}$/\nNew-line&/' infile

Wenn Sie sedeine \nEwline im Ersatzteil immer noch nicht verarbeiten können , können Sie eine aktuelle Newline haben oder Ctrl+ drücken, Vgefolgt von Enterden ^MSteuerzeichen der Eingabetaste:

sed -e ':t;N;$!bt; s/\(\n[^\n]*\)\{2\}$/\
New-line&/' infile

Wie es funktioniert

Das NAnfügen jede Zeile sed den Musterraum lesen , gefolgt von einer neuen Zeile hinzugefügt , bis alle Zeilen lesen. Das :tdefiniert ein Label und $!btsagt sed, springe zum aufgerufenen Label, tsolange es nicht das Ende der Datei ist.


Ich vermute, dass dies mit einer riesigen Eingabedatei und einem großen Nein sehr langsam wird. von Zeilen, die auf das Einfügen folgen ... Genau wie bei Rakeshs Lösung muss dies NEW_LINEvor der Verwendung desinfiziert werden.
don_crissti

4

Es kann einfach gemacht werden headund tail:

$ output=$(head -n -2 file ; echo 'new line' ; tail -2 file)
$ echo "$output" > file

Wie in den Kommentaren erwähnt, frisst es alle nachgestellten Leerzeilen. Um nachgestellte Leerzeilen beizubehalten,

$ head -n -2 file >> file.tmp
$ echo 'new line' >> file.tmp
$ tail -2 file >> file.tmp
$ mv file.tmp file

oder Single Liner

$ head -n -2 file >> file.tmp ; echo 'new line' >> file.tmp; tail -2 file >> file.tmp ; mv file.tmp file

2
Dadurch werden alle nachgestellten Leerzeilen in der Eingabedatei aufgefressen.
don_crissti

@don_crissti Warum werden die nachgestellten Leerzeilen gegessen? Der Befehl innerhalb $(...)funktioniert von selbst einwandfrei. Ist es also die Zuweisung?
Sparhawk


Ich habe die Antwort aktualisiert, jetzt verwende ich die Umleitung anstelle der Befehlsersetzung und natürlich werden nachgestellte Leerzeilen
beibehalten

einfach und leicht zu verstehen
Nam G VU

1

Das Folgende awkkönnte auch helfen.

awk -v line=$(wc -l < Input_file) -v val="new_line" 'FNR==(line-1){print val} 1' Input_file

1

Dieser sollte gegenüber dem Inhalt der eingefügten Zeile recht robust sein, erfordert jedoch, dass die Datei zweimal gescannt wird ( wcfür den ersten Durchgang).

sed "$(($(wc -l < yourfile)-$N))a"'new line' yourfile

0
sed -e '
   1N
   $!{N;P;D;}
   H;g;s/^/NEW_LINE/
' input-data.txt

Wie es funktioniert

  • Halten Sie immer zwei Ines im Musterraum.
  • Drucken Sie die erste der beiden Zeilen im Musterbereich aus, hacken Sie sie ab und lesen Sie die nächste und hängen Sie sie an.
  • Spülen ... Schaum ... Wiederholen, solange die letzte Zeile nicht in den Musterraum eingelesen wurde.
  • An diesem Punkt fügen wir am Anfang eine neue Zeile (\ n) ein und fügen dort die erforderliche Zeichenfolge ein.
  • Dies ist POSIX-ly sed

0
tac input.txt | sed '2 a New line' | tac

Erläuterung

  • tac- druckt Zeilen in umgekehrter Reihenfolge, sodass die letzte Zeile die erste, die last - 1Zeile die zweite usw. wird.
  • sed '2 a New line- New lineNach der zweiten Zeile anhängen .
  • tac - kehrt die Zeilen wieder um.

Testen

$ tac <(seq 1 5) | sed '2 a New line' | tac
1
2
3
New line
4
5
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.