Reemplace una cadena larga con el comando sed: Error de lista de argumentos demasiado larga

Reemplace una cadena larga con el comando sed: Error de lista de argumentos demasiado larga

Estoy intentando ejecutar este comando

sed -i -e "s/BASE_64/$BASE_64/" FILE_NAME

donde $BASE_64es una representación en base 64 del contenido de un archivo.

sedme da error porque la cadena es demasiado larga.

Lista de argumentos demasiado larga

¿Cómo es posible evitar este error?

Respuesta1

Siempre puedes hacer (ya que sedya estás usando GNU ( -i)):

sed -i -f - FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF

-f -le dice sedque lea el script sed desde stdin.

Si desea reutilizar el mismo script para varios archivos, en Linux (y solo Linux), con un shell como zshy kshuna bashversión hasta 5.0 que implementa aquí documentos con archivos temporales (a diferencia de canalizaciones como dasho yash(o bash5.1+) para Heredocs relativamente pequeños y aún con GNU sed, podrías hacer:

find . -name '*.conf' -exec sed -i -f /dev/stdin {} + << EOF
s/BASE_64/$BASE_64/g
EOF

En Linux (y sólo en Linux y Cygwin), /dev/stdinno significaentrada estándarde la misma manera -lo hace. En cambio, es un enlace simbólico al archivo abierto en stdin, por lo que cada vez que sedlo abre, abre el archivo nuevamente desde el principio. El comando anterior funcionaría bien en otros sistemas (que tengan /dev/stdin) o con shells que implementen documentos aquí con canalizaciones, pero solo si hay pocos confarchivos suficientes que sedse llamen solo una vez. Cuando se llama por segunda vez, en sistemas que no son Linux/Cygwin, como con -f -, /dev/stdinaparecería vacío porque ya ha sido leído en la primera invocación.

busybox sedtambién es compatible -ide la misma manera que GNU sed, pero no es compatible -f -. Entonces querrás usarlo -f /dev/stdinallí en cualquier caso. Con FreeBSD sed, utilice:

sed -i '' -f /dev/stdin FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF

Respuesta2

Primero, guarde los datos codificados en base64 en un archivo llamado, por ejemplo, base64.txt.

Por ejemplo:

base64 < originalfile > base64.txt

Entonces:

printf '%s\n' '/BASE64/r base64.txt' 1 '/BASE64/d' w | ed FILENAME

Esto se utiliza edpara buscar FILENAMEuna línea que contiene la cadena BASE64, insertar el contenido base64.txtdespués de esa línea, volver a la primera línea, luego buscar la línea con la cadena BASE64nuevamente y eliminarla. El wcomando edguarda el archivo modificado.

Respuesta3

Otra opción sería reemplazar sedy edalmacenar sus comandos en un archivo. Por ejemplo, si crea ed_cmdscon los siguientes contenidos:

%s/BASE_64/<expanded variable>/g
w
q

entonces podrías correr

< ed_cmds ed FILE_NAME

y haría los cambios que deseaba, por lo que en lugar de configurar, $BASE_64crearía el archivo de comando ed.

Explicación educativa

  • %significa aplicar el comando a cada línea del archivo
  • s/pat1/pat2/gsustituye las apariciones de pat1with pat2y gal final hace que lo haga para cada partido en la línea, no solo el primero
  • wescribir los cambios en el disco
  • qdejar de fumar (lo que sucedería cuando obtuviera EOF de todos modos)

Por supuesto, puede poner sus sedcomandos en un archivo y usarlos -ftambién, pero si está haciendo eso y desea modificar el archivo en su lugar, también puede usarlo eden lugar de crear un archivo temporal y moverlo como lo sed -ihace.

Respuesta4

Terminé poniendo las sedinstrucciones en un archivo.

SEDCOMMANDS=`tempfile`

y llamé

sed -f "$SEDCOMMANDS" -- "$FILE_NAME"

Eso es bueno si no lo usas sed -i. Si desea editar el archivo en su lugar, sigahttps://unix.stackexchange.com/a/284188/149867y coloque las instrucciones equivalentes eden un archivo, seguidas de wy q.

información relacionada