Um comando de amostra que exibe o sintoma: sed 's/./@/' <<<$'\xfc'
falha, porque o byte 0xfc
não é um caractere UTF-8 válido.
Observe que, por outro lado, o GNU sed
(Linux, mas também instalável no macOS) simplesmente passa o byte inválido, sem relatar um erro.
Usar a resposta anteriormente aceita é uma opção se você não se importa em perder o suporte para o seu local verdadeiro (se você estiver em um sistema nos EUA e nunca precisar lidar com caracteres estrangeiros, isso pode ser bom).
No entanto, o mesmo efeito pode ser tido ad-hoc para um único comando única :
LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
Nota: O que importa é uma configuração efetiva LC_CTYPE
de C
, portanto LC_CTYPE=C sed ...
, normalmente também funcionaria, mas, se LC_ALL
for definido (para algo diferente de C
), ele substituirá as LC_*
variáveis de categoria individual , como LC_CTYPE
. Assim, a abordagem mais robusta é definir LC_ALL
.
No entanto, a configuração (efetivamente) LC_CTYPE
de C
tratar sequências de caracteres como se cada byte fosse seu próprio caractere ( nenhuma interpretação baseada em regras de codificação é executada), sem levar em consideração a codificação - multibyte-on-demand - UTF-8 que o OS X emprega por padrão , onde caracteres estrangeiros têm codificações multibyte .
Em poucas palavras: a configuração LC_CTYPE
paraC
faz com que o shell e os utilitários reconheçam apenas letras em inglês básicas como letras (aquelas no intervalo ASCII de 7 bits), de modo que caracteres estrangeiros. não serão tratados como letras , causando, por exemplo, conversões em maiúsculas / minúsculas.
Novamente, isso pode ser bom se você não precisar corresponder a caracteres codificados com vários bytes, como por exemplo é
, e simplesmente desejar passar esses caracteres .
Se isso for insuficiente e / ou você quiser entender a causa do erro original (incluindo a determinação de quais bytes de entrada causaram o problema) e executar conversões de codificação sob demanda, leia abaixo.
O problema é que a codificação do arquivo de entrada não corresponde à do shell.
Mais especificamente, o arquivo de entrada contém caracteres codificados de uma maneira que não é válida em UTF-8 (como @Klas Lindbäck afirmou em um comentário) - é o que a sed
mensagem de erro está tentando dizer invalid byte sequence
.
Muito provavelmente, seu arquivo de entrada usa uma codificação de 8 bits de byte único , como ISO-8859-1
frequentemente usada para codificar idiomas da "Europa Ocidental".
Exemplo:
A letra acentuada à
possui o ponto de código Unicode 0xE0
(224) - o mesmo que em ISO-8859-1
. No entanto, devido à natureza da codificação UTF-8 , esse único ponto de código é representado como 2 bytes - 0xC3 0xA0
, enquanto a tentativa de passar o byte único 0xE0
é inválida em UTF-8.
Aqui está uma demonstração do problema usando a string voilà
codificada como ISO-8859-1
, com a à
representada como um byte (por meio de uma string bash com citação ANSI-C ( $'...'
) usada \x{e0}
para criar o byte):
Observe que o sed
comando é efetivamente um no-op que simplesmente passa a entrada, mas precisamos provocar o erro:
# -> 'illegal byte sequence': byte 0xE0 is not a valid char.
sed 's/.*/&/' <<<$'voil\x{e0}'
Para simplesmente ignorar o problema , a LCTYPE=C
abordagem acima pode ser usada:
# No error, bytes are passed through ('á' will render as '?', though).
LC_CTYPE=C sed 's/.*/&/' <<<$'voil\x{e0}'
Se você deseja determinar quais partes da entrada causam o problema , tente o seguinte:
# 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}'
A saída mostrará todos os bytes com o bit alto definido (bytes que excedem o intervalo ASCII de 7 bits) na forma hexadecimal. (Observe, no entanto, que isso também inclui sequências multibyte UTF-8 codificadas corretamente - uma abordagem mais sofisticada seria necessária para identificar especificamente bytes inválidos em UTF-8.)
Executando conversões de codificação sob demanda :
O utilitário padrão iconv
pode ser usado para converter para codificações ( -t
) e / ou de ( -f
); iconv -l
lista todos os suportados.
Exemplos:
Converta FROM ISO-8859-1
na codificação em vigor no shell (com base em LC_CTYPE
, que é UTF-8
baseada em padrão), com base no exemplo acima:
# Converts to UTF-8; output renders correctly as 'voilà'
sed 's/.*/&/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Observe que essa conversão permite corresponder corretamente caracteres estrangeiros :
# Correctly matches 'à' and replaces it with 'ü': -> 'voilü'
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Para converter a entrada BACK para ISO-8859-1
após o processamento, basta canalizar o resultado para outro iconv
comando:
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')" | iconv -t ISO-8859-1