Un comando de muestra que muestra el síntoma: sed 's/./@/' <<<$'\xfc'
falla, porque el byte 0xfc
no es un carácter UTF-8 válido.
Tenga en cuenta que, por el contrario, GNU sed
(Linux, pero también instalable en macOS) simplemente pasa el byte no válido, sin informar un error.
Usar la respuesta anteriormente aceptada es una opción si no le importa perder el soporte para su ubicación local verdadera (si está en un sistema de EE. UU. Y nunca necesita tratar con caracteres extranjeros, puede estar bien).
Sin embargo, el mismo efecto se puede conseguir ad-hoc para un solo comando solamente :
LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
Nota: Lo que importa es una configuración efectiva LC_CTYPE
de C
, por LC_CTYPE=C sed ...
lo que normalmente también funcionaría, pero si LC_ALL
se establece (en algo diferente a C
), anulará las LC_*
variables de categoría individual como LC_CTYPE
. Por lo tanto, el enfoque más robusto es establecer LC_ALL
.
Sin embargo, (efectivamente) se configura LC_CTYPE
para C
tratar las cadenas como si cada byte fuera su propio carácter ( no se realiza ninguna interpretación basada en reglas de codificación), sin tener en cuenta la codificación UTF-8 - multibyte-on-demand - que OS X emplea de manera predeterminada , donde los caracteres extranjeros tienen codificaciones multibyte .
En pocas palabras: establecer LC_CTYPE
enC
hace que el shell y las utilidades solo reconozcan letras inglesas básicas como letras (las que están en el rango ASCII de 7 bits), por lo que los caracteres extranjeros. no se tratarán como letras , lo que hará que, por ejemplo, las conversiones en mayúsculas / minúsculas fallen.
Una vez más, esto puede estar bien si no necesita hacer coincidir caracteres codificados con varios bytes como é
, y simplemente desea pasar dichos caracteres .
Si esto es insuficiente y / o desea comprender la causa del error original (incluida la determinación de qué bytes de entrada causaron el problema) y realizar conversiones de codificación a pedido, lea a continuación.
El problema es que la codificación del archivo de entrada no coincide con la del shell.
Más específicamente, el archivo de entrada contiene caracteres codificados de una manera que no es válida en UTF-8 (como dijo @Klas Lindbäck en un comentario): eso es lo que el sed
mensaje de error intenta decir invalid byte sequence
.
Lo más probable es que su archivo de entrada utilice una codificación de 8 bits de un solo byte , como la que ISO-8859-1
se usa con frecuencia para codificar idiomas "europeos occidentales".
Ejemplo:
La letra acentuada à
tiene un punto de código Unicode 0xE0
(224), lo mismo que en ISO-8859-1
. Sin embargo, debido a la naturaleza de la codificación UTF-8 , este único punto de código se representa como 2 bytes 0xC3 0xA0
, mientras que intentar pasar el byte único no0xE0
es válido bajo UTF-8.
Aquí hay una demostración del problema usando la cadena voilà
codificada como ISO-8859-1
, con la à
representada como un byte (a través de una cadena bash ( $'...'
) citada por ANSI-C que se usa \x{e0}
para crear el byte):
Tenga en cuenta que el sed
comando es efectivamente un no-op que simplemente pasa la entrada, pero lo necesitamos para provocar el error:
# -> 'illegal byte sequence': byte 0xE0 is not a valid char.
sed 's/.*/&/' <<<$'voil\x{e0}'
Para simplemente ignorar el problema , LCTYPE=C
se puede usar el enfoque anterior :
# No error, bytes are passed through ('á' will render as '?', though).
LC_CTYPE=C sed 's/.*/&/' <<<$'voil\x{e0}'
Si desea determinar qué partes de la entrada causan el problema , intente lo siguiente:
# 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 salida le mostrará todos los bytes que tienen el conjunto de bits alto (bytes que exceden el rango ASCII de 7 bits) en forma hexadecimal. (Sin embargo, tenga en cuenta que eso también incluye secuencias multibyte UTF-8 codificadas correctamente: se necesitaría un enfoque más sofisticado para identificar específicamente bytes no válidos en UTF-8).
Realización de conversiones de codificación bajo demanda :
La utilidad estándar iconv
se puede usar para convertir a ( -t
) y / o desde ( -f
) codificaciones; iconv -l
enumera todos los compatibles.
Ejemplos:
Convierta FROM ISO-8859-1
a la codificación vigente en el shell (basado en LC_CTYPE
, que está UTF-8
basado por defecto), basándose en el ejemplo anterior:
# Converts to UTF-8; output renders correctly as 'voilà'
sed 's/.*/&/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Tenga en cuenta que esta conversión le permite hacer coincidir correctamente los caracteres extranjeros :
# Correctly matches 'à' and replaces it with 'ü': -> 'voilü'
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Para convertir la entrada BACK a ISO-8859-1
después del procesamiento, simplemente canalice el resultado a otro iconv
comando:
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')" | iconv -t ISO-8859-1