Caracteres especiales y archivos unix
Resuelto
Hola,
Tengo un conjunto de archivos
Estos caracteres se transforman en el archivo total a caracteres especiales
¿Hay alguna solución para este problema?
Gracias.
Tengo un conjunto de archivos
.csven Unix. Dentro, hay nombres / palabras que contienen "é" u otros, como por ejemplo "Aurélie". Cuando concateno estos archivos para hacer un solo archivo:
for i in `ls *`TOTO*.csv` ;do cat $i>TOTO.TOTAL.csv done
Estos caracteres se transforman en el archivo total a caracteres especiales
"é".
¿Hay alguna solución para este problema?
Gracias.
6 respuestas
-
ModeradorHola,
Algunos recordatorios previos
Para entender qué es una codificación, es interesante hacer un paralelo con un libro. Un libro puede estar escrito en inglés (en cuyo caso los caracteres ASCII son suficientes) o en francés, ruso o chino (en cuyo caso, se necesita una codificación que permita almacenar los caracteres especiales que resultan).
Esto tiene un impacto: en ASCII, cada carácter se codifica en un byte (8 bits), es decir, 2^8 = 256 posibilidades. Si miramosman ascii
, veremos además que los caracteres acentuados no figuran allí, y eso es lo que motivó la aparición de codificaciones más complejas. Así es como nació Unicode (2 bytes por carácter) y posteriormente formatos más compactos como ISO o UTF-8 (donde los caracteres son de tamaño variable).
En resumen, la codificación es a un archivo lo que un idioma es a una novela.
El problema es que en una computadora, todo no son más que bytes, y por lo tanto, todo depende del significado que se le dé a esos bytes. Sin embargo, como las convenciones adoptadas por estas diferentes codificaciones son distintas (e incompatibles), ahí es donde surgen los problemas de codificación. Cuando observas caracteres cabalísticos (ya sea en el resultado de un comando de shell o en un sitio web mal configurado), en realidad es este famoso problema el que ocurre. El software que decodifica el texto utiliza una codificación A mientras que este archivo ha sido almacenado con una codificación B.
Finalmente, además de los problemas de codificación, puede ocurrir un problema adicional. Los sistemas operativos Linux, BSD, MacOS, etc., utilizan el carácter LF ('\n' en programación) para materializar un retorno de línea, mientras que Windows hace su propia historia y utiliza CRLF ('\r\n' en programación).
El comandocat
Para concatenar varios archivos en shell, en lugar de usar un buclefor
como propones, simplemente escribe:
cat archivo1.csv archivo2.csv archivo3.csv > resultado.csv
Cómo evitar los problemas de codificación
El enfoque es simple: es mejor usar siempre y en todo momento UTF-8 (y ASCII si el archivo no contiene caracteres especiales). Recomiendo para ello asegurarte de que es, por tanto, la configuración regional por defecto (ver el resultado del comandolocale
)
En Debian / Ubuntu, las configuraciones regionales soportadas y la configuración regional por defecto están declaradas como se explica en esta página).
Sin embargo, incluso si tu sistema está configurado para usar la configuración regionalfr_FR.UTF-8
, puede que algunos archivos no se ajusten a UTF-8. Esto se relaciona con:- algunos archivos ya presentes en tu sistema, que no necesitan caracteres especiales, y que, por lo tanto, están codificados en ASCII (como, por ejemplo,
/etc/motd
, el mensaje de bienvenida) - los archivos provenientes de otros lugares (p. ej., de Internet, de una partición de Windows, etc.).
¿Qué codificación se utiliza en un archivo dado, o cuando concateno dos archivos?
Si usas el comandocat
como se explicó anteriormente, la codificación elegida al momento de crear un archivo será generalmente la más apropiada (p. ej., ASCII si tu archivo no contiene caracteres especiales, UTF-8 en caso contrario).
¿Qué pasa si concatenamos dos archivos con codificaciones diferentes? Bueno, depende, pero en general, el software involucrado intentará elegir una codificación que tenga en cuenta las especificidades de cada uno de los archivos. El comandofile
permite ver qué codificación se utiliza:
Ejemplo :
(mando@silk) (~) $ file /etc/motd
/etc/motd: texto ASCII
(mando@silk) (~) $ file toto.txt
toto.txt: texto Unicode UTF-8
(mando@silk) (~) $ cat /etc/motd toto.txt > resultado.txt
(mando@silk) (~) $ file resultado.txt
resultado.txt: texto Unicode UTF-8
En este ejemplo, dado que UTF-8 es estrictamente más tolerante que ASCII y dado que toto.txt contiene caracteres especiales, entonces el archivo resultado.txt se escribe en UTF-8.
Sin embargo, ten cuidado, esto no significa que necesariamente tendrás UTF-8 (incluso si tu configuración regional está bien configurada), solo la codificación más tolerante.
Ejemplo 1 :
(mando@silk) (~) $ file /media/windows/Documents\ and\ Settings/mando/ntuser.ini
/media/windows/Documents and Settings/mando/ntuser.ini: texto Unicode UTF-16 little-endian, con terminadores de línea CRLF
(mando@silk) (~) $ cat /media/windows/Documents\ and\ Settings/mando/ntuser.ini /etc/motd > resultado.txt
(mando@silk) (~) $ file resultado.txt
resultado.txt: texto Unicode UTF-16 little-endian, con terminadores de línea CRLF
Ejemplo 2 :
(mando@silk) (~) $ cat /media/windows/Documents\ and\ Settings/mando/ntuser.ini toto.txt > resultado.txt
(mando@silk) (~) $ file resultado.txt
resultado.txt: texto Unicode UTF-16 little-endian, con terminadores de línea CRLF
En resumen, antes de concatenar archivos de codificación (no ASCII) diferentes, es más prudente corregir su codificación previamente.- Método 1 : el comando
iconv
(que ya has mencionado) permite cambiar la codificación de un archivo. El comandofile
permite ver la codificación utilizada en un archivo de texto. - Método 2 : los editores de texto también permiten (en el momento de guardar el archivo) elegir/cambiar la codificación del archivo de texto. De hecho, si abres un archivo, digamos que está escrito en ASCII y introduces un carácter especial, este será convertido a UTF-8 (de acuerdo con tus configuraciones regionales). Si la codificación previa del archivo ya soportaba caracteres especiales, la codificación no será modificada:
Retornos de línea de Windows
Si miramos el ejemplo 2, vemos que el archivoresultado.txt
contiene retornos de línea de Windows (es decir,\r\n
= CRLF). Como se explicó en la introducción, los otros sistemas operativos (incluido Linux) utilizan\n
= LF.
Aquí también, una conversión previa puede ser necesaria. Personalmente, utilizodos2unix
, pero existen otras maneras de proceder, ver esta discusión).
Ejemplo :
(mando@silk) (~) $ cp /media/windows/devlist.txt .
(mando@silk) (~) $ file devlist.txt
devlist.txt: texto ASCII, con terminadores de línea CRLF, CR
(mando@silk) (~) $ dos2unix devlist.txt
dos2unix: conversión del archivo devlist.txt al formato Unix…
(mando@silk) (~) $ file devlist.txt
devlist.txt: texto ASCII, con terminadores de línea CRLF, LF
Podemos controlar en detalle cómo se modifican los retornos de línea (p. ej., concat -A devlist.txt
).
Buena suerte - algunos archivos ya presentes en tu sistema, que no necesitan caracteres especiales, y que, por lo tanto, están codificados en ASCII (como, por ejemplo,
-
De hecho, es una conversión a UTF-8 sin BOM de mi archivo final (necesario para una transmisión) lo que provoca que tenga estos caracteres especiales:
iconv -f IBM-1252 -t UTF-8 TOTO.TOTAL.csv >TOTO.TOTAL.csv.tmp
La pregunta sigue siendo la misma: ¿cómo evitar estos caracteres especiales? -
Hola mamiemando,
¡Muchas gracias por el gran esfuerzo que has puesto en responderme!
- Para el "cat", utilizo el bucle "for" porque tengo varios, mínimo 20 archivos, el "cat archivo1 archivo2 archivo3" no funciona.
- Los archivos que estoy concatenando son todos del mismo script presente en la misma máquina donde tengo mi problema.
- Lo siento, olvidé mencionar que estoy bajo Unix AIX 7.2 y no Linux, el comando "dos2unix" no funciona "ksh: dos2unix: not found."
Así que lo que encontré es un "sed": sed 's/é/é/' "mi_archivo", no es demasiado bueno, pero me quedan los otros caracteres. -
ModeradorHola dino,
Para "cat", utilizo el bucle "for" porque tengo varios, mínimo 20 archivos, y "cat archivo1 archivo2 archivo3" no funciona.
Para cat: puedes pasar 20 archivos si quieres, no hay problema. Si luego te resulta demasiado tedioso escribir (lo que puedo entender), ten en cuenta que puedes inyectar el resultado de un comando en otro.
Ejemplo:
cat $(ls *csv)
Los archivos que concateno provienen todos del mismo script presente en la misma máquina donde tengo el problema.
Está bien. Esto no cambia nada, dicho esto :-)
Mis disculpas, olvidé mencionar que estoy en Unix AIX 7.2 y no en Linux, el comando "dos2unix" no funciona "ksh: dos2unix: not found."
Probablemente solo necesites instalarlo (en Ubuntu ejecutaríamos:sudo apt update && sudo apt install dos2unix
). Ten en cuenta que este enlace, que propongo anteriormente, sugiere métodos alternativos, por ejemplo, utilizandotr
. Finalmente, ten en cuenta que esta conversión solo es necesaria si tienes problemas con los retornos de línea, no necesariamente estás enfrentando este aspecto del problema, depende de ti verlo con cat -A.
Ejemplo 1: retorno de línea linux (LF = \n = $)
(mando@silk) (~) $ cat -A /etc/motd | head
$
The programs included with the Debian GNU/Linux system are free software;$
the exact distribution terms for each program are described in the$
individual files in /usr/share/doc/*/copyright.$
$
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent$
permitted by applicable law.$
Ejemplo 2: retornos de línea windows (CRLF = \r\n = ^M$)
(mando@silk) (~) $ cat -A /media/windows/devlist.txt | head
USB\ROOT_HUB30\4&108F51C9&0&0^M$
Name: USB Root Hub (xHCI)^M^M$
Driver is running.^M^M$
{5D624F94-8850-40C3-A3FA-A4FD2080BAF3}\VWIFIMP_WFD\5&3E95BAB&0&11^M$
Name: Microsoft Wi-Fi Direct Virtual Adapter^M^M$
Driver is running.^M^M$
ACPI\PNP0C02\1^M$
Name: Motherboard resources^M^M$
Device is currently stopped.^M^M$
ACPI\PNP0C02\2^M$
Buena suerte -
Hola,
Gracias mamiemando.
No tengo permisos para instalar nada en el servidor, no tengo acceso como usuario root, opté por el "SED", sin embargo, tu enlace es bastante bueno.
¡Muchas gracias! -