2017-12-12 8 views
1

Ich habe eine Datei foo Ich möchte bearbeiten. Ich möchte alle Zeilen der Datei vor einem bestimmten Muster entsprechen sollte $node_(2)Ersatzlinien in Datei vor Muster

$node_(0) set X_ 46.188445620285734 
$node_(0) set Y_ 400.0 
# $ns_ at 0.0 "$node_(0) setdest 46.188445620285734 400.0 0.0" 
$ns_ at 4.230260628522046 "$node_(0) setdest 140.0 400.0 11.073898626729083" 
$ns_ at 12.70167232749509 "$node_(0) setdest 140.0 293.81155437971427 11.073898626728642" 
# $ns_ at 22.290747430998636 "$node_(0) setdest 140.0 293.81155437971427 0.0" 
$ns_ at 24.512130351924498 "$node_(0) setdest 140.0 121.22627768528247 11.143254728766196" 
$node_(1) set X_ 284.3754249089888 
$node_(1) set Y_ 400.0 
$ns_ at 0.0 "$node_(1) setdest 358.5058741786957 400.0 10.938908248230844" 
# $ns_ at 6.776768539190925 "$node_(1) setdest 358.5058741786957 400.0 0.0" 
$ns_ at 8.52331532068547 "$node_(1) setdest 400.0 400.0 11.27995015881709" 
$ns_ at 12.201888828288247 "$node_(1) setdest 400.0 341.4941258213043 11.279950158817115" 
# $ns_ at 17.388602719303435 "$node_(1) setdest 400.0 341.4941258213043 0.0" 
$ns_ at 22.22922653365822 "$node_(1) setdest 400.0 141.4941258213043 11.258336966410015" 
$node_(2) set X_ 270.0 //so basically here is the pattern match 
$node_(2) set Y_ 293.0222761518543 
. 
. 
. 

Die Datei dann wie dieses usind

$node_(0) set X_ 10.0 
$node_(0) set Y_ 10.0 
$node_(1) set X_ 510.0 
$node_(1) set Y_ 510.0 
$node_(2) set X_ 270.0 //pattern and everything after it is left intact 
$node_(2) set Y_ 293.0222761518543 
. 
. 
. 

Ich habe versucht, schauen ersetzen Sed

sed -i -e '/$node_(0)/,/$node_(2)/c\$node_(0)\ set X_ 10.0 \n$node_(0) set Y_ 10.0\n$node_(1) set X_ 510.0\n$node_(1) set Y_ 510.0' foo 

aber Es entfernt die erste $node_(2) Zeile vollständig. Außerdem ändert sich die Anzahl der Zeilen vor $node_(2) für jede neue foo Datei, so dass ich die Zeilen nicht jedes Mal zählen kann.

+0

'' $ in einem regulären Ausdruck übereinstimmt Ende der Zeile, mögen Sie '\ $' oder '[$]' verwenden, um ein wörtliches Dollar-Zeichen übereinstimmen. – tripleee

+1

Oh, ich glaube ich verstehe jetzt. Sie möchten alle Zeilen vor der ersten löschen, die Ihrem Muster entsprechen, und sie durch hartcodierte Zeilen ersetzen. Ich empfehle Ihnen, den Befehl sed ['r' zu verwenden (https://www.gnu.org/software/sed/manual/sed.html#index-r-_0028read-file_0029-command) (" Datei lesen "). –

+0

@ BenjaminW. genau! Ich weiß schon, womit ich sie ersetze. Ich werde mir den Link ansehen, den Sie gepostet haben, und sehen, ob ich es zum Laufen bringen kann. – pengu1n

Antwort

1

Mit GNU sed:

sed '0,/$node_(2)/{//!d;s//text to add\n&/}' file 
+1

Vielen Dank! Es funktionierte. (Ein '-i' nach' sed' hinzugefügt, um die Datei zu ändern) – pengu1n

-1

Ich empfehle einen mehrstufigen Prozess. Zuerst müssen Sie die gewünschten Zeilen bereits in einer Datei haben, z. B. header.txt.

Nun finden Zeilennummer der letzten Zeile gelöscht werden soll:

$ first=$(grep -n '^\$node_(2)' test.txt | head -1 | cut -d: -f1) 
$ last=$((first -1)) 

diese Zeilen aus der Datei löschen:

$ sed "1,${first}d" myfile.txt 

Nun Katze die beiden Dateien in eine temporäre Datei und Benennen Sie die temporäre Datei um:

$ cat header.txt myfile.txt > tmp$$ && mv tmp$$ myfile.txt 
+0

Mit einem Regex, um die Zeilennummer einer Zeile zu finden, so dass Sie es in einem anderen Befehl entfernen können, ist entschieden ein Anti-Muster. Dies ist ineffizient, besonders wenn die Dateien groß sind, aber in jedem Fall kann 'sed' Zeilen durch Regex löschen, ganz in Ordnung. – tripleee

2

Invertieren Sie einfach die Logik.

sed -n '1i \ 
$node_(0) set X_ 10.0\ 
$node_(0) set Y_ 10.0\ 
$node_(1) set X_ 510.0\ 
$node_(1) set Y_ 510.0 
    /[$]node_(2)/,$p' file 

Die 1 ist eine Adresse, die die Expression der ersten Zeile auswählt und i ist ein Befehls Text einzufügen. Leider ist der Befehl i nicht vollständig standardisiert, so dass die Implementierungsdetails und die Syntax (insbesondere zum Einfügen mehrerer Zeilen) zwischen den Plattformen unterschiedlich sind. Für die Lesbarkeit und Portabilität, schalen vielleicht zu Perl:

perl -i -ne 'BEGIN { print <<__the_end_of_the_BEGIN__; } 
\$node_(0) set X_ 10.0 
\$node_(0) set Y_ 10.0 
\$node_(1) set X_ 510.0 
\$node_(1) set Y_ 510.0 
__the_end_of_the_BEGIN__ 
    $p=1 if /^\$node_\(2\)/; 
    print if $p;' file 

Sie einen sehr ähnlichen awk-Skript schreiben könnte, aber das bedeutet nicht portably Unterstützung in-Place-Bearbeitung der Datei wie sed -i/perl -i.

Perl verwendet Dollarzeichen als Sigel für skalare Variablen, also müssen diese entkoppelt werden, um buchstäblich gedruckt zu werden, und der reguläre Ausdruck Dialekt ist anders (und erheblich mächtiger) als traditionelle sed oder Awk, aber der einzige Unterschied hier ist, dass Klammern zurückgeblättert oder auf andere Weise maskiert werden müssen.

2

Wenn ich die Zeilen setzen Sie in eine separate Datei replace eingefügt werden soll:

$node_(0) set X_ 10.0 
$node_(0) set Y_ 10.0 
$node_(1) set X_ 510.0 
$node_(1) set Y_ 510.0 

kann ich dies tun: standardmäßig

$ sed -n '/\$node_(2)/,$p' infile | cat replace - 
$node_(0) set X_ 10.0 
$node_(0) set Y_ 10.0 
$node_(1) set X_ 510.0 
$node_(1) set Y_ 510.0 
$node_(2) set X_ 270.0 //so basically here is the pattern match 
$node_(2) set Y_ 293.0222761518543 

Der sed Befehl unterdrückt Druck (-n), dann druckt alle Zeilen aus der ersten Übereinstimmung von \$node_(2) (die $ nicht unbedingt hier notwendig, aber immer eine gute Idee, wenn Sie es nicht als End-of-Line-Anker verwenden) am Ende der Datei ($ Adresse).

Der Befehl cat druckt zuerst Ihre Ersatzdatei, dann die Ausgabe des Befehls sed.

Oder mit der sed r ("read") command (Hut Spitze zu tripleee für die Annahme, die Verwendung von -e):

$ sed -n -e '1r replace' -e '/\$node_(2)/,$p' infile 
$node_(0) set X_ 10.0 
$node_(0) set Y_ 10.0 
$node_(1) set X_ 510.0 
$node_(1) set Y_ 510.0 
$node_(2) set X_ 270.0 //so basically here is the pattern match 
$node_(2) set Y_ 293.0222761518543 

Die Befehle werden in mehr -e Stücke getrennt, wie r etwas pingelig ist, was es als das sieht Dateiname zum Lesen. Es würde brechen, wenn $node_(2) in der allerersten Zeile erscheint, aber wenn das der Fall wäre, könnten Sie Ihre Dateien sowieso einfach verketten.

+0

Das sieht so aus, als ob Sie 'sed r' (wie Sie in einem Kommentar erwähnt haben) verwenden wollen und dann aufgegeben haben. Wie der 'i' Befehl ist' r' schwierig, aber versuchen Sie es mit mehreren '-e' Optionen wie' sed -n -e 1r \\ -e ersetzen.txt -e '/ \ $ node_ (2)/$ p 'infile' (unsicher über die Backslashes nach 'r'?) – tripleee

+0

@tripleee Ich dachte über die Verwendung von' r' nach, aber war nicht sofort klar, nur einmal zu lesen, und ich glaube nicht, dass Sie es tatsächlich tun können a non-GNU sed, siehe https://StackOverflow.com/questions/9970124/sed-to-insert-on-first-match-only - und nach oben schauend, sehe ich, dass SLePort eine solche Lösung vorgeschlagen hat. –

Verwandte Themen