¿Cómo puedo cambiar el código ^ L en muchos archivos en Ubuntu?

8

Tengo muchos archivos XML, más de 50000 de ellos.

En algunos archivos XML, algunos archivos se escriben así

<filename>abc.JPEG<^Lilename>

^Les solo un personaje, pero no puedo encontrar lo que ^Lsignifica con Google.

Cuando uso catpara imprimir el contenido de un archivo, se muestra como el siguiente

<filename>abc.JPEG<
                   ilename>

De todos modos, quiero cambiar <filename>abc.JPEG<^Lilename>a<filename>abc.JPEG</filename>

Ya encontré algún comando para cambiar una palabra en muchos archivos, como

find . -exec perl -pi -e 's/[find_word]/[change_word]/g' {} \;

Pero ese comando no funciona en mi caso, porque no puede reconocer la palabra de búsqueda cuando escribo ^L.

¿Cómo puedo cambiar <filename>abc.JPEG<^Lilename>a <filename>abc.JPEG</filename>muchos archivos?

Yang
fuente
66
Aparentemente, alguien lo usó en <\filename>lugar de </filename>en un contexto en el \fque se interpretaría como el personaje del formulario. Probablemente deberías rastrear la fuente de estos archivos y señalar el problema con su herramienta de generación al desarrollador. Para arreglar los archivos, la respuesta aceptada está bien.
Hans-Martin Mosner

Respuestas:

17

Control-L (representado como ^L) es el carácter de "avance de formulario". En ASCII, tiene un valor decimal 12 ( Les la 12ª letra del alfabeto) o un valor hexadecimal 0c:

$ printf 'foo\x0cbar\n' | cat -et
foo^Lbar$

$ printf 'foo\x0cbar\n'
foo
   bar

Puede reemplazarlo utilizando herramientas como sed especificando el código de escape hexadecimal:

$ printf 'foo\x0cbar\n' | sed 's/\x0c//'
foobar

Alternativamente, componga ^Ldirectamente usando la secuencia del teclado CTRL+ V CTRL+L

sed 's/CTRL+VCTRL+L//'

Para su reemplazo específico, dado

$ printf '<\x0cilename\n'
<
 ilename

entonces

$ printf '<\x0cilename\n' | sed 's/<\x0c/<\/f/g'
</filename

(el gmodificador se agrega en caso de que haya más de una instancia por línea).

conductor de acero
fuente
En mi caso, "$ printf '<\ x0cilename \ n' | sed 's / <\ x0c / <\\ f / g'" no funciona. Pero, de acuerdo con su respuesta, "$ find. -Exec perl -pi -e 's / <\ x0cilename> / <\ / filename> / g' {} \;" funciona bien. Gracias por su respuesta :)
Yang
@Yang lo siento, me acabo de dar cuenta de que confundí la barra diagonal y la barra diagonal inversa en mi respuesta (corregida ahora) - todavía no estoy seguro de por qué eso habría impedido que la versión sed funcionara
steeldriver
Una muy buena respuesta! Sería aún mejor si incluyera un findmensaje que recorriera esos 50000 archivos XML y procesara automáticamente cada uno (y también hiciera una copia de seguridad).
Kingsley
2

Como Hans-Martin Mosner señala en los comentarios, parece que alguien usó barras diagonales inversas en lugar de barras diagonales hacia adelante al generar el XML (o posiblemente ejecutó toda la <filename>sección a través de un convertidor de Unix a Windows que estaba demasiado celoso de las barras). \fes una secuencia de escape raramente utilizada para un personaje de alimentación de formulario, también conocido como U + 0C o ^ L. Entonces, algún paso posterior de la tubería luego reemplazó los caracteres \fliterales U + 0C.

Afortunadamente, U + 0C es un personaje extremadamente raro que es poco probable que se encuentre intencionalmente en ningún tipo de XML. Y ya que sólo \fproduciría esto, en lugar de (por ejemplo) \go \k, un hallazgo y reemplazo universal, debe fijar no sólo </filename>, sino también </folder>, </file>o cualquier otra cosa que quedó destrozado.

Eso es lo que hace el script sed de steeldriver; Simplemente lo haría un poco más general:

sed 's|\x0c|/f|g'

Esto significa "(s) wap todas las instancias de \x0c(es decir, U + 0C) a /f, (g) lobally".

Draconis
fuente
2

\fes el carácter de alimentación de formulario en Perl. Parece que estos archivos con formato incorrecto fueron creados por alguien nuevo en Perl y XML.

Aquí hay una solución mucho más Perlier, que también cumple con los objetivos del OP de automatizar la actualización de todos los archivos, a diferencia de la respuesta aceptada con sed, que solo funcionará en un archivo a la vez, ya que no está emparejado find.

\fsimplemente puede emplearse en lugar del código hexadecimal x0c.

find . -type f -exec perl -pi.bkp -e 's [ \f ilename ][ /f ilename ]gx' {} \;

Aquí agregué -type fa tel findpara que solo devuelva archivos sin formato; de lo contrario find, volverá a aparecer .en la lista y activará una advertencia cuando intente editarlo, aunque todo lo demás seguirá funcionando.

También hice que la expresión regular sea más fácil de ver usando la xbandera que ignora el espacio en blanco real, lo que le permite espaciar los elementos de su expresión regular. Si no te gusta esto, aquí está sin:

find . -type f -exec perl -pi.bkp -e 's[\filename][/filename]g' {} \;

Y en el caso probable de que todos los caracteres de alimentación de formularios sean espurios y todos deben ser reemplazados por /f, entonces puede reducir aún más la línea:

find . -type f -exec perl -pi.bkp -e 's[\f][/f]g' {} \;

No necesita utilizar barras diagonales para rodear los elementos de su comando de sustitución de expresiones regulares ( s///) en Perl. Puedes usar cualquier símbolo. Sin embargo, si elige usar cualquier tipo de símbolo pareado entre paréntesis, debe usar ambos: s[old][new]por ejemplo.

Como no estoy usando barras, no tengo que escapar de ninguna barra.

En cuanto a -i.bkp: le perl -pi -epermite editar en el lugar, pero si desea un seguro adicional en caso de que su programa Perl de buscar y reemplazar sea incorrecto, puede colocar una extensión de archivo para que haga una copia de los archivos originales para tú. Aquí lo he usado .bkp.

En las versiones más recientes de Perl, la edición en el lugar se ha actualizado para que sea más resistente en caso de que su sistema sufra un problema grave como pérdida de energía o quedarse sin espacio en disco. Aquí está el autor de Perl, brian d foy, sobre la edición in situ mejorada en Perls recientes.

Debería considerar usar Perl para este tipo de tareas, porque es un lenguaje de programación de propósito general extremadamente potente pero subestimado, uno de cuyos objetivos de diseño originales era reemplazar sedy awkcon algo mucho mejor.

Las capacidades de coincidencia de expresiones regulares de Perl 5 y la sintaxis de expresiones regulares mejoradas superan con creces las de sed, awky de hecho cualquier otro lenguaje de programación, aparte de Perl 6, lo que hace que Perl sea la opción más sensata para manipulaciones de expresiones regulares simples y avanzadas.

Para aclarar: sedtambién funcionará bien findy también puede usar sed -i.bkppara hacer una copia de seguridad de cada archivo editado, pero que yo sepa, no presenta la resistencia adicional en Perl 5.28 y superior. También utiliza la sintaxis tradicional de expresiones regulares de UNIX ® más clunkier y mucho menos potente.

Medlock Perlman
fuente