RE error: séquence d'octets illégale sur Mac OS X

j'essaie de remplacer une chaîne dans un Makefile sur Mac OS X pour la compilation croisée avec iOS. La chaîne comporte des guillemets. La commande est:

sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure

et l'erreur est:

sed: RE error: illegal byte sequence

j'ai essayé d'échapper aux doubles guillemets, guillemets, tirets, et colons sans joie. Par exemple:

sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure

j'ai du mal à résoudre le problème. Est-ce que quelqu'un sait comment obtenir sed pour imprimer position de la séquence d'octets illégale? Ou personne ne sait ce que le illégales séquence d'octets est?

136
demandé sur jww 2013-10-08 12:03:05

5 réponses

un exemple de commande qui montre le symptôme: sed 's/./@/' <<<$'\xfc' échoue, parce que byte 0xfc n'est pas un UTF-8 char valide.

Notez que, par contraste, GNU sed (Linux, mais également installable sur macOS) passe simplement le byte invalide, sans signaler une erreur.

en utilisant le réponse précédemment acceptée est une option si vous ne si vous êtes sur un système américain et que vous n'avez jamais besoin de traiter avec des caractères étrangers, cela peut être très bien.)

cependant, le même effet peut être EU ad-hoc pour un commande unique seulement :

LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure

Remarque: Ce qui compte c'est un efficace LC_CTYPE définition de C , de sorte LC_CTYPE=C sed ... serait normalement fonctionne aussi, mais si LC_ALL arrive à être défini (à quelque chose d'autre que C ), il supplantera individuel LC_* - les variables de catégorie telles que LC_CTYPE . Ainsi, l'approche la plus robuste consiste à fixer LC_ALL .

Cependant, (efficacement) paramètre LC_CTYPE à C traite des chaînes comme si chaque octet étaient son propre caractère ( non une interprétation basée sur des règles d'encodage est effectuée), avec no regard pour le - multibyte-on-demand - UTF-8 encoding que OS X emploie par défaut, où caractères étrangers ont multibyte encodings .

En un mot: réglage LC_CTYPE à C les causes de la coque et des utilitaires pour seulement reconnaître un anglais de base des lettres lettres (celles de la gamme 7-bit ASCII), de sorte que caractères étrangers. ne sera pas traité comme les lettres , provoquant, par exemple, des conversions en majuscules/minuscules à l'échec.

encore une fois , ce peut être très bien si vous n'avez pas besoin de match multibyte-encoded characters such as é , et veulent simplement passer de tels caractères par .

Si cela est insuffisant et/ou vous voulez comprendre la cause de l'erreur d'origine (y compris la détermination de ce que les octets d'entrée est la cause du problème) et effectuer les conversions d'encodage sur demande", 1519560920" lire sur ci-dessous.


le problème est que l'encodage du fichier d'entrée ne correspond pas à celui du shell.

Plus précisément, le fichier d'entrée contient des caractères codés d'une manière qui est pas valide en UTF-8 (comme @Klas Lindbäck l'a déclaré dans un commentaire) - c'est ce que le message d'erreur sed essaie de dire par invalid byte sequence .

très probablement, votre fichier d'entrée utilise un encodage simple 8 bits tel que ISO-8859-1 , fréquemment utilisé pour coder les langues" D'Europe occidentale".

exemple:

la lettre accentuée à a Unicode code 0xE0 (224) - le même que dans ISO-8859-1 . Cependant, en raison de la nature de UTF-8 encodage, ce codepoint unique est représenté comme 2 octets - 0xC3 0xA0 , alors que d'essayer de passer le byte simple 0xE0 est invalide sous UTF-8.

Voici une démonstration du problème utilisation de la chaîne voilà codé comme ISO-8859-1 , avec le à représenté comme un byte (via une chaîne de bash ANSI-C-quoted ( $'...' ) qui utilise \x{e0} pour créer le byte):

notez que la commande sed est effectivement une no-op qui passe simplement l'entrée, mais nous en avons besoin pour provoquer l'erreur:

  # -> 'illegal byte sequence': byte 0xE0 is not a valid char.
sed 's/.*/&/' <<<$'voil\x{e0}'

simplement ignorer le problème , le au-dessus de LCTYPE=C approche peut être utilisée:

  # No error, bytes are passed through ('á' will render as '?', though).
LC_CTYPE=C sed 's/.*/&/' <<<$'voil\x{e0}'

si vous voulez déterminer quelles parties de l'entrée causent le problème , essayez ce qui suit:

  # Convert bytes in the 8-bit range (high bit set) to hex. representation.
  # -> 'voil\x{e0}'
iconv -f ASCII --byte-subst='\x{%02x}' <<<$'voil\x{e0}'

la sortie vous montrera tous les bytes qui ont le jeu de bits élevé (bytes qui dépassent la gamme 7-bit ASCII) dans la forme hexadécimale. (Il convient toutefois de noter que cela inclut également les séquences multi-octets UTF - 8 correctement encodées-une approche plus sophistiquée serait nécessaire pour identifier spécifiquement les octets invalides-in-UTF-8.)


effectuer des conversions d'encodage à la demande :

standard utility iconv peut être utilisé pour convertir en ( -t ) et/ou à partir de ( -f ) encodages; iconv -l liste tous ceux supportés.

exemples:

convertir de ISO-8859-1 en l'encodage en vigueur dans le shell (basé sur LC_CTYPE , qui est UTF-8 -basé par défaut), basé sur l'exemple ci-dessus:

  # Converts to UTF-8; output renders correctly as 'voilà'
sed 's/.*/&/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"

notez que cette conversion vous permet de faire correspondre correctement les caractères étrangers :

  # Correctly matches 'à' and replaces it with 'ü': -> 'voilü'
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"

pour convertir l'entrée en ISO-8859-1 après traitement, simplement Piper le résultat à une autre iconv commande:

sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')" | iconv -t ISO-8859-1
242
répondu mklement0 2018-05-15 04:38:23

ajoutez les lignes suivantes à vos fichiers ~/.bash_profile ou ~/.zshrc .

export LC_CTYPE=C 
export LANG=C
113
répondu binarytemple_picsolve 2013-11-04 14:54:06

la réponse de mklement0 est géniale, mais j'ai quelques petites retouches.

il semble être une bonne idée de spécifier explicitement le codage de bash en utilisant iconv . En outre, nous devrions préparer une marque d'ordre d'octet ( même si la norme unicode ne le recommande pas ) parce que il peut y avoir des confusions légitimes entre UTF-8 et ASCII sans une marque d'ordre d'octet . Malheureusement, iconv ne prépose pas de marque d'ordre de byte lorsque vous spécifiez explicitement une endianness ( UTF-16BE ou UTF-16LE ), nous devons donc utiliser UTF-16 , qui utilise une endianness spécifique à la plate-forme, puis utiliser file --mime-encoding pour découvrir la véritable endianness iconv utilisé.

(Je majuscule tous mes encodages parce que quand vous listez tous les encodages supportés de iconv avec iconv -l ils sont tous majuscules.)

# Find out MY_FILE's encoding
# We'll convert back to this at the end
FILE_ENCODING="$( file --brief --mime-encoding MY_FILE )"
# Find out bash's encoding, with which we should encode
# MY_FILE so sed doesn't fail with 
# sed: RE error: illegal byte sequence
BASH_ENCODING="$( locale charmap | tr [:lower:] [:upper:] )"
# Convert to UTF-16 (unknown endianness) so iconv ensures
# we have a byte-order mark
iconv -f "$FILE_ENCODING" -t UTF-16 MY_FILE > MY_FILE.utf16_encoding
# Whether we're using UTF-16BE or UTF-16LE
UTF16_ENCODING="$( file --brief --mime-encoding MY_FILE.utf16_encoding )"
# Now we can use MY_FILE.bash_encoding with sed
iconv -f "$UTF16_ENCODING" -t "$BASH_ENCODING" MY_FILE.utf16_encoding > MY_FILE.bash_encoding
# sed!
sed 's/.*/&/' MY_FILE.bash_encoding > MY_FILE_SEDDED.bash_encoding
# now convert MY_FILE_SEDDED.bash_encoding back to its original encoding
iconv -f "$BASH_ENCODING" -t "$FILE_ENCODING" MY_FILE_SEDDED.bash_encoding > MY_FILE_SEDDED
# Now MY_FILE_SEDDED has been processed by sed, and is in the same encoding as MY_FILE
3
répondu Heath Borders 2017-05-23 12:26:34

ma solution avait été D'utiliser Perl:

find . -type f -print0 | xargs -0 perl -pi -e 's/was/now/g'
1
répondu Vitaly Zdanevich 2018-02-19 15:52:56

ma solution avait été d'utiliser gnu sed . A bien fonctionné pour mes fins.

0
répondu lu_zero 2016-08-31 05:44:44