2 votos

Elimina todos los saltos de línea que siguen al retorno de carro (^M) y une las líneas

edit: Ahora que tengo respuestas, he marcado una de @KamilMaciorowski que se ajusta mejor al título como respuesta, pero esta respuesta de @oliv en realidad se adaptaban mejor a mi necesidad real a mi propósito principal. (Procesar un archivo csv con pausas de forma consistente en awk).

Así que en el caso de que estuvieras buscando awking en una circunstancia similar, te recomiendo que compruebes eso primero.


Por favor, ayúdenme a preparar unos cuantos miles de archivos csv listos para awk ¡para procesar! Algunos de los campos tienen saltos de línea dentro del campo y eso está causando awk para procesarlos como un registro múltiple. Sin embargo, esos saltos de línea problemáticos sólo ocurren cuando se inserta ^M, por lo que sólo es necesario eliminar ^M y el salto de línea de todos ellos.

*Estos ^M son en realidad caracteres de salto de línea, no una cadena literal de caret y letra M. Este archivo se genera para que .net lo analice y procese, pero no he trabajado en el desarrollo de aplicaciones en ninguno de los dos lados de producción/lectura de archivos, así que no sé realmente cómo se analiza con éxito. Se utiliza exclusivamente para los campos de ciertas columnas con cadenas de líneas múltiples (comentarios).

Entonces, ¿cómo se hace esto (csv con 1 encabezado y 2 registros. Algunos campos tienen saltos de línea precedidos por ^M):

"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a^M
2-2_b^M
2-2_c", "2-3"

¿así? (csv con 1 cabecera y 2 registros sin saltos de línea dentro de cada uno de ellos):

"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a2-2_b2-2_c", "2-3"

Intenté eliminarlos con sed pero escuché que no hay manera de procesar, y no entendí bien la razón.

for file in *.csv; do
    sed -e "s/^M//" $file > sedded/$file;
done

De todos modos, entiendo esto:

"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a
2-2_b
2-2_c", "2-3"

Intenté ir por algo como "s/^M\n/" y no funciona como sospechaba. ¿Debo utilizar una herramienta completamente diferente como vim ? Mientras funcione para miles de archivos a la vez (cada uno de los cuales contiene ~500 líneas, y realmente no me importa el tiempo que se tarda en procesar) estoy bien con cualquier tipo de resolución. Sólo pensaba sed era el camino. (No tengo problema en usar el comando DOS/powershell si es más fácil o más sencillo).

0 votos

Es ^M ¿una cadena literal o un carácter de control (nueva línea)?

0 votos

@oliv Gracias por preguntar, voy a actualizar: es la nueva línea que inserta la aplicación que genera los archivos csv. Las utiliza en campos con comentarios de varias líneas. Es principalmente para que la aplicación .net lo analice y no sé cómo interpretan estos archivos, pero es así. (¿Probablemente sea más fácil procesar esto en una máquina Windows? Estoy bien con eso también si ese es el caso).

0 votos

@KamilMaciorowski Oh dang eso es correcto gracias por notar, estoy arreglando eso.

4voto

Kamil Maciorowski Puntos 897

Si estos ^M -s son efectivamente caracteres de salto de línea, no cadenas literales de caret y letra M, entonces son lo que denotamos \r , CR o 0x0d (comparar esta respuesta mía, el comienzo de la misma ).

Su mando

sed -e "s/^M//"

no elimina \r ; ni siquiera elimina los literales ^M . El comando significa "toma una línea, busca una letra M que está al principio de la línea ( ^ , ver esto ), sustitúyalo por nada.

Nota sed entiende \r . Todavía sed -e 's/\r//' no es exactamente lo que necesitas. Elimina \r pero hay que eliminar lo siguiente \n también. Puede que quieras probar sed -e 's/\r\n//' Esto también fallará. El problema es sed es una herramienta de texto y trata \n como separador. Extracto de info sed (énfasis mío):

sed opera realizando el siguiente ciclo en cada línea de entrada: primero, sed lee una línea del flujo de entrada, elimina cualquier línea nueva final y lo coloca en el espacio del patrón. A continuación, los comandos se ejecutan; [ ].

Esto significa que normalmente \n no pertenece a ninguna cadena procesada con s/… (u otro sed ). Por esta razón, concatenar pocas líneas no es fácil. Sin embargo, se puede hacer . Este es el comando que necesitas:

sed -e ': start; /\r$/{ s/\r$//; N; s/\n// }; /\r$/b start'

Explicación:

  • : start es una etiqueta.
  • Si la línea contiene \r (es decir ^M , 0x0d ) al final ( $ ), ejecute el {} bloque que es:
    • sustituir \r al final sin nada,
    • añadir una línea adicional de la entrada ( N ),
    • sustituir \n que separa la línea adicional de los datos anteriores.
  • Si el resultado contiene \r al final (lo que significa que la línea adicional la trajo, por lo que necesitamos añadir otra línea más), salta a start .

1 votos

Gracias, ha funcionado perfectamente. Y gracias también por la explicación. Todavía no los entiendo bien y cómo funciona su respuesta, pero voy a investigar. Para tu información, mi comando elimina ^M successfully when I use Control+V (verbatim insert) to denote ^M no es el literal M al principio de la línea.

2voto

oliv Puntos 156

Asumiendo que hay 3 campos en cada fila, y que no hay ninguna comilla doble dentro de ningún valor, podrías usar este GNU awk script:

awk -v FPAT='"[^"]*"' '{while(NF!=3){p=$0;getline;gsub("^",p)}; p=""}1' file

FPAT define el aspecto de un campo, es decir, todo lo que está rodeado de comillas dobles.

La sentencia awk construye un registro obteniendo líneas del archivo hasta que haya 3 campos.

0 votos

Esto no funcionaba sólo porque tenía que manejar también algunos campos vacíos, así que utilicé -F, en lugar de eso, ¡y funcionó! De hecho, este fue el primer día que usé awk, así que estoy aliviado de saber lo poderosa que es esta herramienta. ¡Muchas gracias!

0 votos

Esta es una elección muy difícil. Para mí técnicamente esta respuesta es definitivamente la mejor ya que esta línea resolvió todo el problema de una vez (sin usar bucle, sed cualquier otra cosa en absoluto), sin embargo, sólo por el bien de la referencia que coincide con mi título de la pregunta y la respuesta, me temo que estoy eligiendo otro.. Estoy demasiado corto de reputación para upvote y tal, pero voy a notar acerca de esto en mi pregunta. ¡Lo siento, y gracias!

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by: