Ce code:
for root, dirs, files in os.walk('.'):
print(root)
Me donne cette erreur:
UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 27: surrogates not allowed
Comment puis-je parcourir un arbre de fichiers sans obtenir des chaînes toxiques comme celle-ci?
Sous Linux, les noms de fichiers ne sont «qu'un tas d'octets» et ne sont pas nécessairement encodés dans un encodage particulier. Python 3 essaie de tout transformer en chaînes Unicode. Ce faisant, les développeurs ont mis au point un système permettant de traduire les chaînes d'octets en chaînes Unicode et inversement sans perte et sans connaître l'encodage d'origine. Ils ont utilisé des substituts partiels pour coder les «mauvais» octets, mais le codeur UTF8 normal ne peut pas les gérer lors de l'impression sur le terminal.
Par exemple, voici une chaîne d'octets non UTF8:
>>> b'C\xc3N'.decode('utf8','surrogateescape')
'C\udcc3N'
Il peut être converti vers et à partir d'Unicode sans perte:
>>> b'C\xc3N'.decode('utf8','surrogateescape').encode('utf8','surrogateescape')
b'C\xc3N'
Mais cela ne peut pas être imprimé:
>>> print(b'C\xc3N'.decode('utf8','surrogateescape'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 1: surrogates not allowed
Vous devrez déterminer ce que vous voulez faire avec les noms de fichiers avec des encodages autres que ceux par défaut. Peut-être juste les encoder à nouveau en octets originaux et les décoder avec un remplacement inconnu. Utilisez-le pour l'affichage mais conservez le nom d'origine pour accéder au fichier.
>>> b'C\xc3N'.decode('utf8','replace')
C�N
os.walk
peut également prendre une chaîne d'octets et renverra des chaînes d'octets au lieu de chaînes Unicode:
for p,d,f in os.walk(b'.'):
Ensuite, vous pouvez décoder comme vous le souhaitez.
J'ai fini par passer une chaîne d'octets à os.walk()
qui renverra apparemment des chaînes d'octets au lieu de chaînes unicode incorrect
for root, dirs, files in os.walk(b'.'):
print(root)
Filtrer avec sed
ou grep
:
set | sed -n '/^[a-zA-Z0-9_]*=/p'
# ... or ...
set | grep '^[a-zA-Z0-9_]*='
# ... or ...
set | egrep '^[_[:alnum:]]+='
Cela dépend de la folie de vos noms de variables. La dernière version devrait gérer la plupart des choses folles.