Sed replace nur in geraden Zeilen einer Datei, wenn Ersetzungsbefehle in eine Datei geschrieben werden

Sed replace nur in geraden Zeilen einer Datei, wenn Ersetzungsbefehle in eine Datei geschrieben werden

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 sedBefehle 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 sedvon verwenden sollen :first~step

Adressen

    … Folgende Adresstypen werden unterstützt: …

    Erste~Schritt
      Übereinstimmung mit jedemSchritt'te Zeile beginnend mit ZeileErste. Beispielsweise sed -n 1~2pdruckt „ “ 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 Fall sedfunktioniert es, als wäre es gleich Schritt. (Dies ist eine Erweiterung.)

Die offensichtliche Lösung wäre, jedem Befehl in replace.sedein 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_listreplace.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 umgewandelt 2~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)

sedVariante, alle Befehle jeder Zeile in einer Befehlsgruppe zusammenzufassen .

Aber auch dies schlägt fehl, wenn replace.sedes 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.sedDatei 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.sedoder sehr komplexen Befehlen ein Problem gäbe.

verwandte Informationen