Wie kann ich die letzten n Zeilen in einer Datei bearbeiten?

10

Gibt es einen Befehl, mit dem ich die letzten n Zeilen in einer Datei bearbeiten kann? Ich habe mehrere Dateien, die alle eine unterschiedliche Anzahl von Zeilen enthalten. Aber ich möchte die letzten n Zeilen in jeder Datei ändern. Ziel ist es, Kommas in den letzten n Zeilen durch Semikolons zu ersetzen. Aber nur in den letzten n Zeilen.

Ich möchte keine Zeilen löschen, sondern nur jedes Komma durch ein Semikolon in den letzten n Zeilen jeder Datei ersetzen.

Mit dem Befehl sed kann ich die allerletzte Zeile durch diesen Befehl ersetzen. Wie hier beschrieben: Wie kann ich Text in der letzten Zeile einer Datei entfernen?

Dies ermöglicht mir jedoch nur, die allerletzte Zeile und nicht die letzte n Anzahl von Zeilen zu ändern.

sku2003
quelle
1
Einfach mit sed '24,$s/,/:/g' filename wo 24ist die Startlinie?
Valentin Bajrami

Antworten:

13

So ersetzen Sie Kommas durch Semikolons in den letzten n Zeilen durch ed:

n=3
ed -s input <<< '$-'$((n-1))$',$s/,/;/g\nwq'

Das aufteilen:

  • ed -s = still ausgeführt (melden Sie nicht die am Ende geschriebenen Bytes)
  • '$-'= vom Ende der Datei ( $) minus ...
  • $((n-1)) = n-1 Zeilen ...
  • ( $' ... '= zitiere den Rest des Befehls, um ihn vor der Shell zu schützen)
  • ,$s/,/;/g= ... bis zum Ende der Datei ( ,$) suchen und alle Kommas durch Semikolons ersetzen.
  • \nwq = Beenden Sie den vorherigen Befehl, speichern Sie ihn und beenden Sie ihn

So ersetzen Sie Kommas durch Semikolons in den letzten n Zeilen durch sed:

n=3
sed -i "$(( $(wc -l < input) - n + 1)),\$s/,/;/g" input

Das auseinander brechen:

  • -i = bearbeite die Datei "an Ort und Stelle"
  • $(( ... )) = rechne nach:
  • $( wc -l < input) = Anzahl der Zeilen in der Datei ermitteln
  • -n + 1 = gehe n-1 Zeilen rückwärts
  • ,\$ = von n-1 Zeilen bis zum Ende der Datei:
  • s/,/;/g = Ersetzen Sie die Kommas durch Semikolons.
Jeff Schaller
quelle
Kann ersetzen wc -l < inputmit wc -l input. Sollte um ein paar Nanosekunden schneller sein :)
Gardenhead
1
außer dass auch wc -l inputder Dateiname ausgegeben wird; wir wollen nur die Zeilenanzahl
Jeff Schaller
Der erste Rat mit ed ist gut und einfach.
sku2003
Ich bekam tatsächlich Hilfe von einer ganz anderen Seite. Dies führte zu diesem seltsamen Stück Code, der den Trick macht, aber lang und seltsam ist. Ich denke, dies sind einige seltsame Dinge, mit denen Sie am Ende eine Lösung zusammenstellen können. Wie auch immer, deine ist hübscher, kürzer und weniger kompliziert als meine: Der Code hier hat auch funktioniert:
sku2003
cat input.file | sed 's /, /, \ n / g' | sed -n '1! G; h; $ p' | awk -vn = 2 'NR <= n {gsub (",", ";", $ 0)} {print}' | sed -n '1! G; h; $ p' | sed '/ ^ \ s * $ / d'> output.file
sku2003
6

Lösung mit tac und sed , um jedes Komma in den letzten 50 Zeilen von file.txt durch ein Semikolon zu ersetzen:

tac file.txt | sed '1,50s/,/;/g' | tac
Gohu
quelle
5

Mit GNU headund einer Bourne-ähnlichen Hülle:

n=20
{ head -n -"$n"; tr , ';'; } < file 1<> file

Wir überschreiben die Datei über sich selbst. Das ist in Ordnung hier für eine Byte-zu-Byte - Umschrift , aber nicht notwendigerweise , wenn die Änderung bedeutet die Größe der Datei zu ändern (in diesem Fall würden Sie ersetzen mögen 1<> filemit > other-file && mv other-file filezum Beispiel).

Stéphane Chazelas
quelle
1
Hier sind Dokumente1<> , mit denen ich nicht vertraut war. Auch spongeaus moreutils ist ein gutes Werkzeug für Rohrleitungen , wo Sie wollen Ihre Eingaben zu überschreiben.
Meilen
1

Nehmen wir an, wir möchten die letzten 7Zeilen der folgenden Sequenz durch ein Shell-Skript und eine GNU-Implementierung von ersetzen sed:

$ seq 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Schritt 1 : Lassen Sie uns die letzte Zeilennummer der Sequenz wie folgt abrufen. Schauen Sie sich dies und das an :

$ lastLine=`seq 20|sed -n '$='`

$ echo $lastLine 
20

Schritt 2 : Legen Sie die Anzahl der Zeilen (am Ende der Sequenz) fest, die wir bearbeiten möchten:

$ numberOfLines=7

$ echo $numberOfLines 
7

Schritt 3 : Lassen Sie uns die Startlinie basierend auf vorherigen Variablen wie folgt berechnen. Schauen Sie sich auf diese :

$ startLine=`expr $lastLine - $numberOfLines + 1`

$ echo $startLine 
14

Schritt 4 : Jetzt können wir die letzten 7 Zeilen der Sequenz durch etwas anderes ersetzen, wie das folgende. Schauen Sie sich auf diese :

$ seq 20|sed -e "$startLine,+$numberOfLines{s/[12]/WoW/}"
1
2
3
4
5
6
7
8
9
10
11
12
13
WoW4
WoW5
WoW6
WoW7
WoW8
WoW9
WoW0

In Schritt 4 wird Abschnitt 4.4 der sed-Manpage verwendet, in dem Folgendes angegeben ist:

'ADDR1,+N'
     Matches ADDR1 and the N lines following ADDR1.

In Schritt 4 werden auch doppelte Anführungszeichen verwendet, wie hier erwähnt .


Nun, die 4 Schritte sind unnötig, wenn wir die Antwort von Gohu so verwenden:

$ seq 20 |tac|sed -e '1,7{s/[12]/WoW/}'|tac
1
2
3
4
5
6
7
8
9
10
11
12
13
WoW4
WoW5
WoW6
WoW7
WoW8
WoW9
WoW0
user3405291
quelle
0

Verwenden Sie tailund leiten Sie zu sed:

tail -n 20 file | sed 's/,/;/g'

Dies funktioniert in der Datei für die letzten 20 Zeilen. Wenn Sie möchten, dass Sie direkt in die Datei wechseln, verwenden Sie:

tail -n 20 file | sed -i 's/,/;/g'

John Goofy
quelle