![Sed replace nur in geraden Zeilen einer Datei, wenn Ersetzungsbefehle in eine Datei geschrieben werden](https://rvso.com/image/1416716/Sed%20replace%20nur%20in%20geraden%20Zeilen%20einer%20Datei%2C%20wenn%20Ersetzungsbefehle%20in%20eine%20Datei%20geschrieben%20werden.png)
Ich habe alle Ersetzungsbefehle in einer Datei (sagen wir replace.sed) und verwende sie mit dem Flag -f von sed (sed -f replace.sed InputFile). Aber jetzt bin ich in eine Situation geraten, in der ich diese Ersetzungsregeln nur auf gerade nummerierte Zeilen einer gegebenen Eingabedatei anwenden muss (also nur auf Zeile 2, 4, 6 usw.). Ich kann keine Bedingungsanweisungen in die Datei replace.sed einfügen, da diese auch von anderen Skripten verwendet wird.
Antwort1
Verwenden Sie die Prozessersetzung, um die sed
Befehle in Ihrer Datei im Handumdrehen anzupassen:
$ cat replace.sed
s#foo#bar#
.
$ printf "foo\nfoo\nfoo\nfoo\n" | sed -f replace.sed
bar
bar
bar
bar
.
$ printf "foo\nfoo\nfoo\nfoo\n" | sed -f <(sed 's#^#2~2#g' replace.sed)
foo
bar
foo
bar
Antwort2
sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed) InputFile
Antwort3
Was die anderen Antworten Ihnen sagen möchten, ist, dass Sie die Adressform sed
von verwenden sollen :first~step
Adressen
… Folgende Adresstypen werden unterstützt: …
Erste~SchrittÜbereinstimmung mit jedemSchritt'te Zeile beginnend mit ZeileErste. Beispielsweise
sed -n 1~2p
druckt „ “ alle ungeraden Zeilen im Eingabestrom und die Adresse „2~5
“ stimmt mit jeder fünften Zeile überein, beginnend mit der zweiten. Erstekann Null sein; in diesem Fallsed
funktioniert es, als wäre es gleich Schritt. (Dies ist eine Erweiterung.)
Die offensichtliche Lösung wäre, jedem Befehl in replace.sed
ein 2~2
(oder 0~2
, wenn es in Ihrer Version von funktioniert sed
) voranzustellen, damit die Befehle in jeder zweiten Zeile ausgeführt werden, beginnend mit der zweiten (d. h. alle geraden Zeilen im Eingabestrom, wie Sie gefordert haben). Aber Sie sagen, dass Sie nicht ändern können replace.sed
. Nun, der nächste Schritt (wie in den anderen Antworten angegeben, aber nicht erklärt) besteht darin, eine vorübergehende temporäre Datei mit den Shell-Informationen zu erstellen.ProzesssubstitutionFähigkeit, wobei es sich wie eine Datei verhält, die die Ausgabe von ist . Wenn es sich, wie Ihre Frage nahelegt, nur um eine Folge einfacher Ersatzbefehle handelt, dann
<(command_list)
command_list
replace.sed
sed -f <(sed 's/^/2~2/g' replace.sed)
sollte arbeiten.
Dies hat jedoch Nachteile:
- Wenn Sie mehrere Befehle pro Zeile haben, betrifft das Obige nur den ersten Befehl in jeder Zeile.
- Wenn Sie Befehle mit numerischen Adressen haben (z. B.
42s/Zaphod/Beeblebrox/
), werden diese beispielsweise in umgewandelt2~242…
, mit der offensichtlichen Konsequenz. - Und wenn Sie Befehle mit nicht numerischen Adressen haben (z. B.
/windows/s/command/cmd/
), schlägt das Obige sofort fehl.
Wenn einer dieser Fälle zutrifft, verwenden Sie die
sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed)
sed
Variante, alle Befehle jeder Zeile in einer Befehlsgruppe zusammenzufassen .
Aber auch dies schlägt fehl, wenn replace.sed
es sich um mehrzeilige Befehle handelt.
Aufbauend auf den oben genannten Ideen kam ich auf
sed -f <(echo '0~2{'; cat replace.sed; echo '}')
das stellt diegesamte replace.sed
Datei in eine Befehlsgruppe. Bei meinen oberflächlichen Tests scheint dies die Bedenken auszuräumen, die ich bei den anderen Lösungen geäußert habe. Es würde mich nicht schockieren, wenn es bei sehr langen replace.sed
oder sehr komplexen Befehlen ein Problem gäbe.