Un exemple de commande qui présente le symptôme: sed 's/./@/' <<<$'\xfc'
échoue, car l'octet 0xfc
n'est pas un caractère UTF-8 valide.
Notez que, en revanche, GNU sed
(Linux, mais également installable sur macOS) passe simplement l'octet invalide, sans signaler d'erreur.
L'utilisation de la réponse précédemment acceptée est une option si cela ne vous dérange pas de perdre la prise en charge de votre véritable locale (si vous êtes sur un système américain et que vous n'avez jamais besoin de gérer des caractères étrangers, cela peut être bien.)
Cependant, le même effet peut être obtenu ad hoc pour une seule commande uniquement :
LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
Remarque: Ce qui compte, c'est un réglage efficace LC_CTYPE
de C
, donc LC_CTYPE=C sed ...
cela fonctionnerait normalement aussi, mais s'il LC_ALL
se trouve être défini (sur autre chose que C
), il remplacera les LC_*
variables de catégorie individuelles telles que LC_CTYPE
. Ainsi, l'approche la plus robuste est de définir LC_ALL
.
Cependant, le réglage (effectivement) LC_CTYPE
sur C
traite les chaînes comme si chaque octet était son propre caractère ( aucune interprétation basée sur des règles de codage n'est effectuée), sans égard pour le codage UTF-8 multi-octets à la demande qu'OS X utilise par défaut , où les caractères étrangers ont des encodages multi - octets .
En un mot: le réglage LC_CTYPE
surC
fait que le shell et les utilitaires ne reconnaissent que les lettres anglaises de base comme des lettres (celles de la plage ASCII 7 bits), de sorte que les caractères étrangers. ne seront pas traités comme des lettres , ce qui entraînera, par exemple, l'échec des conversions majuscules / minuscules.
Encore une fois, cela peut convenir si vous n'avez pas besoin de faire correspondre des caractères codés sur plusieurs octets tels que é
, et que vous souhaitez simplement passer ces caractères .
Si cela est insuffisant et / ou si vous souhaitez comprendre la cause de l'erreur d'origine (y compris déterminer quels octets d'entrée ont causé le problème) et effectuer des conversions de codage à la demande, lisez la suite ci-dessous.
Le problème est que le codage du fichier d'entrée ne correspond pas à celui du shell.
Plus précisément, le fichier d'entrée contient des caractères encodés d'une manière qui n'est pas valide en UTF-8 (comme @Klas Lindbäck l'a déclaré dans un commentaire) - c'est ce que le sed
message d'erreur essaie de dire invalid byte sequence
.
Très probablement, votre fichier d'entrée utilise un codage 8 bits à un octet tel que ISO-8859-1
, fréquemment utilisé pour coder les langues «d'Europe occidentale».
Exemple:
La lettre accentuée à
a un point de code Unicode 0xE0
(224) - le même que dans ISO-8859-1
. Cependant, en raison de la nature du codage UTF-8 , ce point de code unique est représenté par 2 octets - 0xC3 0xA0
, alors que tenter de passer l' octet unique 0xE0
est invalide sous UTF-8.
Voici une démonstration du problème en utilisant la chaîne voilà
codée comme ISO-8859-1
, avec le à
représenté comme un octet (via une chaîne bash entre guillemets ANSI-C ( $'...'
) qui utilise \x{e0}
pour créer l'octet):
Notez que la sed
commande est effectivement un no-op qui passe simplement l'entrée, mais nous en avons besoin pour provoquer l'erreur:
sed 's/.*/&/' <<<$'voil\x{e0}'
Pour ignorer simplement le problème , l' LCTYPE=C
approche ci-dessus peut être utilisée:
LC_CTYPE=C sed 's/.*/&/' <<<$'voil\x{e0}'
Si vous souhaitez déterminer quelles parties de l'entrée sont à l'origine du problème , essayez ce qui suit:
iconv -f ASCII --byte-subst='\x{%02x}' <<<$'voil\x{e0}'
La sortie vous montrera tous les octets qui ont le bit haut défini (octets qui dépassent la plage ASCII 7 bits) sous forme hexadécimale. (Notez, cependant, que cela inclut également les séquences multioctets UTF-8 correctement codées - une approche plus sophistiquée serait nécessaire pour identifier spécifiquement les octets non valides en UTF-8.)
Effectuer des conversions d'encodage à la demande :
L'utilitaire standard iconv
peut être utilisé pour convertir des encodages en ( -t
) et / ou à partir de ( -f
); iconv -l
répertorie tous ceux pris en charge.
Exemples:
Convertissez FROM ISO-8859-1
en encodage en vigueur dans le shell (basé sur LC_CTYPE
, qui est UTF-8
basé par défaut), en vous basant sur l'exemple ci-dessus:
sed 's/.*/&/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Notez que cette conversion vous permet de faire correspondre correctement les caractères étrangers :
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Pour convertir l'entrée BACK en ISO-8859-1
après traitement, dirigez simplement le résultat vers une autre iconv
commande:
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')" | iconv -t ISO-8859-1