5 minutos
Convertir Finales De Linea
Introducción
Cada sistema operativo tiene una forma distinta para indicar el fin
de línea de un archivo. En sistemas Windows se usan los caracteres
\r\n
, en unix (aunque de ahora en adelante usaremos linux
indistintamente) es el carácter \n
y en macOS se usa \r
. Cuando
abrimos un archivo generado en un sistema operativo diferente al
nuestro, es muy probable que el texto se vea escalonado o no presente
la misma estructura (esto también depende del editor que usemos, ya
que algunos identifican el final de línea del archivo y hacen la
conversión al sistema actual antes de mostrarlo). Pero el problema no
es únicamente visual, hay herramientas para manejo de texto que
esperan que los archivos terminen con un carácter en particular; el
comando grep
de linux es una muestra de esto, ya que espera que los
archivos terminen únicamente con el carácter \n
y si no lo está no
tendremos los resultados esperados.
Resumen de caracteres de fin de línea
Sistema Operativo | Fin de Línea |
---|---|
Linux | \n |
MacOS | \r |
Windows | \r\n |
El problema al usar expresiones regulares
Siguiendo con el ejemplo de grep
, trataremos de buscar la cadena
Emacs rocks
al final de la línea. Esto se hace con una expresión
regular muy sencilla: Emacs rocks$
. El símbolo $
al final indica
fin de línea, por lo que podemos leer nuestra expresión regular como
“encuentra la frase Emacs rocks seguido del fin de
línea”. Supongamos que tenemos un archivo (editors.txt) con una lista
de editores de texto, seguido de un eslogan:
Intellij, made with love from Rusia
Eclipse, always happy to consume your RAM
Emacs, simple put, Emacs rocks
Podemos usar nuestra expresión regular con grep de la siguiente
manera: grep "Emacs rocks$" editors.txt
solo para descubrir que no
obtuvimos resultados. Pero al abrir el archivo vemos que Emacs
rocks existe, y está al final de la línea, ¿Entonces por qué no
aparece en los resultados de grep
?. En este caso en particular el
archivo editors.txt
fue creado en windows, por lo que cada línea
termina en \r\n
y como ya comentamos grep
espera que el fin de
línea sea únicamente \n
, y todo lo anterior a eso lo considera parte
de la línea, entonces para grep
el archivo se ve así:
Intellij, made with love from Rusia\r
Eclipse, always happy to consume your RAM\r
Emacs, simple put, Emacs rocks\r
En este caso, podemos incluir el carácter \r
en nuestra expresión regular:
$> grep $'Emacs rocks\r$' editors.txt
Aquí el primer $
no es parte de la expresión regular, es una
indicación para el shell de que tome un carriage return literalmente
si lo encuentra dentro de los apóstrofes.
Convertir el archivo a nuestro formato de fin de línea
Lo primero que tenemos que hacer es identificar el tipo de archivo,
para eso utilizaremos el comando file
:
$> file editors.txt
editors.txt: ISO-8859 text, with CRLF line terminators
file
no solo nos indica la codificación del archivo, también nos
dice el tipo de fin de línea del mismo, en este caso CRLF
(Carriage
Return y Line Feed), o lo que es lo mismo \r\n
. Veamos algunas
formas para convertir el archivo a fin de línea de linux.
dos2unix
Este es un programa que tiene muchos años realizando esta tarea, es muy sencillo y efectivo. Para instalarlo desde debian o derivados:
$> sudo apt install dos2unix
Y la forma de ejecutarlo es muy simple:
$> dos2unix editors.txt
dos2unix: convirtiendo archivo editors.txt a formato Unix...
Para comprobar que la conversión tuvo éxito, ejecutamos nuevamente
file
:
$> file editors.txt
editors.txt: ISO:8859 text
Si esto lo comparamos con la salida anterior, veremos que la frase with CRLF terminators desapareció, lo que quiere decir que se convirtió exitosamente.
sed
dos2unix
básicamente busca los caracteres \r\n
y los reemplaza por
\n
, y esto lo podemos hacer nosotros mismos, usando sed
:
$> sed $'s/\r\n/\n/g' -i editors.txt
Al igual que como hicimos en el ejemplo con grep
tuvimos que usar
$'...'
para que \r
sea interpretado correctamente.
Emacs
También podemos hacer la conversión desde nuestro editor
favorito. Cuando abrimos un archivo creado en windows veremos al final
de cada línea los símbolos ^M
, este es el equivalente en Emacs para
carriage return (y el equivalente para line feed es ^J
). Para
hacer el cambio de fin de línea tenemos varias opciones, y las
veremos enseguida.
Reabrir el archivo con el formato correcto
Si ya tenemos abierto el archivo, la forma más sencilla de convertirlo
es con la función revert-buffer-with-coding-system
, que puede ser
invocado con C-x C-m r dos
.
Reemplazando el texto
Podemos usar el comando para reemplazar texto (query-replace
),
generalmente asigna a las teclas M-%
:
M-x query-replace C-q C-m RET
usando elisp
Si queremos convertir automáticamente los archivos al abrirlos, la siguiente función hace el truco:
(defun no-junk-please-were-unixish ()
(let ((coding-str (symbol-name buffer-file-coding-system)))
(when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
(set-buffer-file-coding-system 'unix))))
(add-hook 'find-file-hooks 'no-junk-please-were-unixish)
O podemos indicar el tipo de codificación manualmente con
set-buffer-coding-system
, para hacer un poco más fácil de recordar
se puede usar el siguiente código:
(defun dos2unix ()
"Not exactly but it's easier to remember"
(interactive)
(set-buffer-file-coding-system 'unix 't) )
Conclusión
Existen muchas formas de convertir los finales de línea, las que yo compartí no son las únicas, pero tal vez sean las más prácticas.