Caractères spéciaux et fichiers unix

Résolu/Fermé
dino - Modifié le 1 sept. 2021 à 14:34
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 - 8 sept. 2021 à 11:32
Bonjour,

J'ai un ensemble de fichiers
.csv
sous Unix. Dedans, il y' a des noms / mots qui ont des "é" ou autres, comme par exemple "Aurélie". Quand je concatène ces fichiers la pour faire un seul fichiers :

for i in `ls *`TOTO*.csv` ;do
  cat $i>TOTO.TOTAL.csv
done


Ces caractères se transforment dans le fichier total en caractère spéciaux
"é"
.

Y'a-t'il une solution a ce problème ?

Merci.
A voir également:

6 réponses

mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
Modifié le 1 sept. 2021 à 13:56
Bonjour,

Quelques rappels préalables

Pour comprendre ce qu'est un encodage, il est intéressant de faire le parallèle avec un livre. Un livre peut être écrit en anglais (auquel cas les caractères ASCII suffisent) ou en français, en russe ou en chinois (auquel cas, un encodage permettant de stocker les caractères spéciaux qui en résulte est nécessaire).

Cela a un impact : en ASCII, chaque caractère est codé sur un octet (8 bits), soit 2^8 = 256 possibiltés. Si on regarde
man ascii
, on verra en outre que les caractères accentués n'y figurent pas, et c'est ce qui a motivé l'apparitions d'encodage plus compliqués. C'est comme ça qu'est né l'unicode (2 octets par caractère) et par la suite des formats plus compacts comme l'ISO ou l'UTF8 (ou les caractères sont de taille variables).

Bref, l'encodage est à un fichier ce qu'une langue est à un roman.

Le problème, c'est que sur un ordinateur, tout n'est qu'octet, et donc tout dépend du sens qu'on donne à ces octets. Or comme les conventions prises par ces différents encodages sont différentes (et incompatibles), c'est là que les problèmes d'encodage arrivent. Lorsque tu observes des caractères cabalistiques (soit dans le résultat d'une commande shell, soit sur un site internet mal configuré), c'est en réalité le ce fameux problème qui survient. Le logiciel qui décode le texte utilise un encodage A alors que ce fichier a été stocké avec un encodage B.

Enfin, en plus des problèmes d'encodage, un problème supplémentaire peut avoir lieu. Les systèmes d'exploitations Linux, BSD, MacOS, etc utilisent le caractère LF ('\n' en programmation) pour matérialiser un retour à la ligne, alors que windows fait bande à part et utilise CRLF ('\r\n' en programmation).

La commande
cat


Pour concaténer plusieurs fichiers en shell, plutôt qu'utiliser une boucle
for
comme tu le proposes, il suffit d'écrire :

cat fichier1.csv fichier2.csv fichier3.csv > resultat.csv


Comment éviter les problème d'encodage

La démarche est simple : il vaut mieux toujours utiliser partout et tout le temps de l'UTF-8 (et de l'ASCII si le fichier ne contient pas de caractères spéciaux). Je recommande pour cela de s'assurer que c'est donc bien la locale par défaut (voir le résultat de la commande
locale
)

Sous Debian / Ubuntu, les locales supportés et la locale par défaut sont déclarées comme expliquées dans cette page).

Toutefois, même si ton système est configuré pour utiliser la locale
fr_FR.UTF-8
, il se peut que des fichiers ne se conforment pas à de l'UTF-8. Cela concerne :
  • certains fichiers déjà présents sur ton système, qui n'ont pas besoin de caractères spéciaux, et qui sont donc encodés en ASCII (comme par exemple
    /etc/motd
    , le message d'accueil)
  • les fichiers provenant d'ailleurs (e.g. d'Internet, d'une partition windows, etc).


Quel encodage est utilisé dans un fichier donné, ou quand je concatène deux fichiers ?

Si tu utilises la commande
cat
comme expliqué plus haut, l'encodage choisi au moment de créer un fichier sera généralement le plus approprié (e.g. ASCII si ton fichier ne contient pas de caractères spéciaux, UTF-8 sinon).

Que se passe t'il si on concatène deux fichiers avec des encodages différents ? Eh bien ça dépend, mais en gros, le logiciel impliqué essaiera de choisir un encodage qui permet de tenir compte des spécificités de chacun des fichiers. La commande
file
permet de voir quel encodage est utilisé :

Exemple :

(mando@silk) (~) $ file /etc/motd 
/etc/motd: ASCII text
(mando@silk) (~) $ file toto.txt
toto.txt: UTF-8 Unicode text
(mando@silk) (~) $ cat /etc/motd toto.txt > resultat.txt
(mando@silk) (~) $ file resultat.txt
resultat.txt: UTF-8 Unicode text


Dans cet exemple, comme UTF-8 est strictement plus tolérant qu'ASCII et comme toto.txt contient des caractères spéciaux, alors le fichier resultat.txt est écrit en UTF-8.

Attention toutefois, cela ne veut pas dire que tu auras forcément de l'UTF-8 (même si ta locale est bien configurée), juste l'encodage le plus tolérant.

Exemple 1 :

(mando@silk) (~) $ file /media/windows/Documents\ and\ Settings/mando/ntuser.ini 
/media/windows/Documents and Settings/mando/ntuser.ini: Little-endian UTF-16 Unicode text, with CRLF line terminators
(mando@silk) (~) $ cat /media/windows/Documents\ and\ Settings/mando/ntuser.ini /etc/motd > resultat.txt
(mando@silk) (~) $ file resultat.txt
resultat.txt: Little-endian UTF-16 Unicode text, with CRLF line terminators


Exemple 2 :

(mando@silk) (~) $ cat /media/windows/Documents\ and\ Settings/mando/ntuser.ini toto.txt > resultat.txt 
(mando@silk) (~) $ file resultat.txt
resultat.txt: Little-endian UTF-16 Unicode text, with CRLF line terminators


Bref, avant de concaténer des fichiers d'encodage (non ASCII) différents, il est plus prudent de corriger leur encodage au préalable.
  • Méthode 1 : la commande
    iconv
    (que tu as déjà citée) permet de changer l'encodage d'un fichier. La commande
    file
    permet de voir l'encodage utilisé dans un fichier texte.
  • Méthode 2 : Les éditeurs textes permettent aussi (au moment de sauver le fichier) de choisir/changer l'encodage du fichier texte. D'ailleurs, si tu ouvres un fichier disons écris en ASCII et que tu introduis un caractère spécial, celui-ci sera converti en UTF-8 (conformément à tes locales). Si l'encodage préalable du fichier supportait déjà les caractères spéciaux, l'encodage ne sera pas modifié :


Retours à la ligne windows

Si on regarde l'exemple 2, on voit que le fichier
resultat.txt
contient des retours à la ligne windows (donc
\r\n
= CRLF). Comme expliqué en introduction les autres systèmes d'exploitations (dont Linux) utilisent
\n
= LF.

Ici aussi, une conversion préalable peut alors s'avérer nécessaire. Personnellement j'utilise
dos2unix
, mais il existe d'autres manières de procéder, voir cette discussion).

Exemple :

(mando@silk) (~) $ cp /media/windows/devlist.txt .
(mando@silk) (~) $ file devlist.txt
devlist.txt: ASCII text, with CRLF, CR line terminators
(mando@silk) (~) $ dos2unix devlist.txt
dos2unix: conversion du fichier devlist.txt au format Unix…
(mando@silk) (~) $ file devlist.txt
devlist.txt: ASCII text, with CRLF, LF line terminators


On peut notamment contrôler en détail comment sont modifiés les retours à la ligne (e.g. avec
cat -A devlist.txt
).

Bonne chance
1
En fait, c'est une conversion en UTF-8 sans BOM de mon fichier final (besoin pour une transmission) qui fait que j'ai ces caractères spéciaux :

iconv -f IBM-1252 -t UTF-8 TOTO.TOTAL.csv >TOTO.TOTAL.csv.tmp


La question reste la même : comment éviter ces caractères spéciaux ?
0
comment éviter ces caractères spéciaux ?

C'est simple : ne pas en mettre (ou traduire en anglais). Je n'en ai pas eu besoin dans ce texte.
0
Bonjour mamiemando ,

Merci beaucoup pour le grand effort que vous avez mis pour me répondre !

- Pour le "cat" , j'utilise la boucle "for" par ce que j’en ai plusieurs min 20 fichiers , le « cat fichier1 fichier2 fichier3 » ne passe pas.
- les fichier que je concatènes sont tous issue du même scripts présent dans la même machine ou j’ai mon problème
- autant pour moi, j’ai oublié de préciser que je suis sous Unix AIX 7.2 et nom Linux ,la commande « dos2unix » ne passe pas « ksh: dos2unix: not found."

Donc ce que j’ai trouvé est une « sed » : sed 's/é/é/' « mon_fichier » , ce n’est pas trop top , mais il me reste les autres caractères .
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
2 sept. 2021 à 12:53
Bonjour dino,

Pour "cat" , j'utilise la boucle "for" par ce que j’en ai plusieurs, minimum 20 fichiers , et « cat fichier1 fichier2 fichier3 » ne passe pas.

Pour cat : tu peux passer 20 fichiers si tu veux ça ne pose pas de problème. Si ensuite tu trouves ça trop fastidieux à taper (ce que je peux comprendre), sache que tu peux injecter le résultat d'une commande dans une autre.

Exemple :

cat $(ls *csv)



Les fichiers que je concatène sont tous issus du même script présent dans la même machine ou j’ai mon problème

Ok. Ça ne change rien ceci dit :-)

Au temps pour moi, j’ai oublié de préciser que je suis sous Unix AIX 7.2 et nom Linux ,la commande « dos2unix » ne passe pas « ksh: dos2unix: not found."

Il faut sans doute juste l'installer (sous Ubuntu on lancerait :
sudo apt update && sudo apt install dos2unix
). Note que ce lien, que j'ai proposé auparavant, propose des méthodes alternatives, e.g. en utilisant
tr
. Note enfin que cette conversion n'est nécessaire que si tu as des soucis au niveau des retours à la ligne, tu n'es pas forcément confronté à cet aspect du problème, à toi de voir avec cat -A.

Exemple 1 : retour à la ligne 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.$


Exemple 2 : retours à la ligne 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$


Bonne chance
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Bonjour,

Merci mamiemando.
Je n'ai pas les droits pour installer quoi que ce soit sur le serveur ,pas du user root , j'ai opté pour le "SED" , par contre ton lien est pas mal

Merci beaucoup !
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
8 sept. 2021 à 11:32
De rien, bonne continuation :-)
0