Sed reemplaza solo en líneas pares de un archivo cuando los comandos de reemplazo están escritos en un archivo

Sed reemplaza solo en líneas pares de un archivo cuando los comandos de reemplazo están escritos en un archivo

Tengo todos los comandos de reemplazo en un archivo (por ejemplo, reemplazar.sed) y lo uso con el indicador -f de sed (sed -f reemplazar.sed InputFile). Pero ahora me encontré con una condición en la que necesito aplicar estas reglas de reemplazo solo en líneas pares de un archivo de entrada determinado (es decir, solo en las líneas 2,4,6, etc.). No puedo poner ninguna declaración de condición en reemplazo. .sed, ya que también lo utilizan otros scripts.

Respuesta1

Utilice la sustitución de procesos para adaptar los sedcomandos en su archivo sobre la marcha:

$ 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

Respuesta2

sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed) InputFile

Respuesta3

Lo que las otras respuestas te dicen que intentas decirte es que utilices sedel formulario de dirección:first~step

Direcciones

    … Se admiten los siguientes tipos de direcciones: …

    primero~paso
      Combina cadapaso'ésima línea que comienza con la líneaprimero. Por ejemplo, " sed -n 1~2p" imprimirá todas las líneas impares en el flujo de entrada y la dirección " 2~5" coincidirá con cada quinta línea, comenzando con la segunda.  primeropuede ser cero; en este caso, sedopera como si fuera igual a paso. (Esta es una extensión).

La solución obvia sería anteponer cada comando replace.sedcon 2~2 (o 0~2, si funciona en su versión de sed) para que los comandos funcionen en cada dos líneas, comenzando con la segunda (es decir, todas las líneas pares en el flujo de entrada, como usted pidió). Pero dices que no puedes modificar replace.sed. Bueno, el siguiente paso (como se identifica, pero no se explica, en las otras respuestas) es crear un archivo temporal transitorio con el shellSustitución de procesoscapacidad, donde actúa como un archivo que es la salida de . Si, como sugiere su pregunta, es solo una secuencia de comandos sustitutos simples, entonces <(command_list)command_listreplace.sed

sed -f <(sed 's/^/2~2/g' replace.sed)

Deberia trabajar.

Pero esto tiene inconvenientes:

  • Si tiene varios comandos por línea, lo anterior afectará solo al primer comando de cada línea.
  • Si tiene comandos con direcciones numéricas (por ejemplo, 42s/Zaphod/Beeblebrox/), se convertirán, por ejemplo, en 2~242…, con la consecuencia obvia.
  • Y si tiene comandos con direcciones no numéricas (por ejemplo, /windows/s/command/cmd/), lo anterior fallará por completo.

Si se aplica alguno de estos casos, debe utilizar el

sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed)

variación para poner todos los sedcomandos en cada línea en un grupo de comandos.

Pero incluso esto fallará si replace.sedtiene comandos de varias líneas.

Sobre la base de las ideas anteriores, se me ocurrió

sed -f <(echo '0~2{'; cat replace.sed; echo '}')

que pone elcompleto replace.sedarchivo en un grupo de comandos. En mis pruebas superficiales, esto parece abordar las preocupaciones que planteé con las otras soluciones. No me sorprendería que tuviera problemas con replace.sedcomandos muy largos o muy complejos.

información relacionada