Sed reemplazar solo en líneas pares de un archivo cuando los comandos de reemplazo se escriben en un archivo

3

Tengo todos los comandos de reemplazo en un archivo (digamos replace.sed) y lo uso con -f flag of sed (sed -f replace.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 dado (es decir, solo en la línea no 2,4,6 y así sucesivamente). No puedo poner ninguna declaración de condición en reemplazo archivo .sed ya que es utilizado por otros scripts también.

Abhishek
fuente

Respuestas:

1

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
Adrian Frühwirth
fuente
1
sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed) InputFile
Ciro
fuente
1

Lo que las otras respuestas le dicen que intenta decirle es usar sedel formulario de dirección:first~step

Direcciones

    ... Se admiten los siguientes tipos de direcciones: ...

    primer ~ paso
      Haga coincidir cada paso con la línea que comienza con la línea primero . Por ejemplo, " sed -n 1~2p" imprimirá todas las líneas impares en la secuencia de entrada, y la dirección " 2~5" coincidirá con cada quinta línea, comenzando con la segunda.  primero puede ser cero; en este caso, sedopera como si fuera igual al  paso . (Esta es una extensión).

La solución obvia sería preceder a cada comando replace.sedcon 2~2 (o 0~2, si funciona en su versión de sed) para hacer que los comandos operen en cualquier otra línea, comenzando con la segunda (es decir, todas las líneas pares en la secuencia de entrada, como usted pidió). Pero dices que no puedes modificar replace.sed. Bueno, el siguiente paso (según lo identificado, pero no explicado, por las otras respuestas) es crear un archivo temporal transitorio con la capacidad de sustitución de proceso del shell , donde actúa como un archivo que es el resultado 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 solo afectará al primer comando en 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 alguno de estos casos se aplica, debe usar 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 todo el replace.sed archivo en un grupo de comandos. En mis pruebas superficiales, esto parece abordar las preocupaciones que planteé con las otras soluciones. No me sorprendería si tiene un problema con un replace.sedcomando muy largo o muy complejo.

Scott
fuente