Un comando di esempio che mostra il sintomo: sed 's/./@/' <<<$'\xfc'
fallisce, perché byte 0xfc
non è un carattere UTF-8 valido.
Si noti, al contrario, GNU sed
(Linux, ma installabile anche su macOS) passa semplicemente attraverso il byte non valido, senza segnalare un errore.
L'uso della risposta precedentemente accettata è un'opzione se non ti dispiace perdere il supporto per la tua locale (se sei su un sistema americano e non hai mai bisogno di trattare con personaggi stranieri, potrebbe andare bene).
Tuttavia, lo stesso effetto può essere dovuto ad-hoc per un singolo comando solo :
LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
Nota: Ciò che conta è una efficace LC_CTYPE
impostazione C
, quindi LC_CTYPE=C sed ...
sarebbe normalmente anche il lavoro, ma se LC_ALL
capita di essere impostato (a qualcosa di diverso C
), avrà la precedenza singole LC_*
variabili -Categoria quali LC_CTYPE
. Pertanto, l'approccio più solido è quello di impostare LC_ALL
.
Tuttavia, l'impostazione (efficacemente) LC_CTYPE
di C
trattare le stringhe come se ogni byte fosse il proprio carattere ( non viene eseguita alcuna interpretazione basata sulle regole di codifica), senza tener conto della codifica UTF-8 multibyte su richiesta che OS X utilizza per impostazione predefinita , in cui i caratteri stranieri hanno codifiche multibyte .
In breve: l' impostazione LC_CTYPE
inC
modo che la shell e le utility riconoscano solo le lettere inglesi di base come lettere (quelle nell'intervallo ASCII a 7 bit), in modo che i caratteri stranieri. non saranno trattati come lettere , causando, ad esempio, conversioni maiuscole / minuscole.
Ancora una volta, questo può andare bene se non è necessario abbinare caratteri con codifica multibyte come é
e se si desidera semplicemente passare tali caratteri attraverso .
Se questo è insufficiente e / o si desidera comprendere la causa dell'errore originale (inclusa la determinazione di quali byte di input hanno causato il problema) ed eseguire conversioni di codifica su richiesta, leggere di seguito.
Il problema è che la codifica del file di input non corrisponde alla shell.
Più specificamente, il file di input contiene caratteri codificati in un modo che non è valido in UTF-8 (come affermato da @Klas Lindbäck in un commento) - questo è ciò che il sed
messaggio di errore sta cercando di dire invalid byte sequence
.
Molto probabilmente, il file di input utilizza una codifica a 8 bit a byte singolo comeISO-8859-1
, utilizzata frequentemente per codificare le lingue "dell'Europa occidentale".
Esempio:
La lettera accentata à
ha un punto di codice Unicode 0xE0
(224) - lo stesso di in ISO-8859-1
. Tuttavia, a causa della natura della codifica UTF-8 , questo singolo punto di codice è rappresentato come 2 byte 0xC3 0xA0
, mentre il tentativo di passare il singolo byte non0xE0
è valido in UTF-8.
Ecco una dimostrazione del problema utilizzando la stringa voilà
codificata come ISO-8859-1
, con il à
rappresentato come un byte (tramite una stringa bash quotata ANSI-C ( $'...'
) che utilizza \x{e0}
per creare il byte):
Si noti che il sed
comando è effettivamente una no-op che passa semplicemente attraverso l'input, ma ne abbiamo bisogno per provocare l'errore:
# -> 'illegal byte sequence': byte 0xE0 is not a valid char.
sed 's/.*/&/' <<<$'voil\x{e0}'
Per ignorare semplicemente il problema , è LCTYPE=C
possibile utilizzare l'approccio sopra :
# No error, bytes are passed through ('á' will render as '?', though).
LC_CTYPE=C sed 's/.*/&/' <<<$'voil\x{e0}'
Se si desidera determinare quali parti dell'input causano il problema , provare quanto segue:
# 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}'
L'output mostrerà tutti i byte con il bit alto impostato (byte che superano l'intervallo ASCII a 7 bit) in forma esadecimale. (Si noti, tuttavia, che include anche sequenze multibyte UTF-8 correttamente codificate: sarebbe necessario un approccio più sofisticato per identificare specificamente i byte non validi in UTF-8.)
Esecuzione della codifica delle conversioni su richiesta :
L'utilità standard iconv
può essere utilizzata per convertire in ( -t
) e / o da ( -f
) codifiche;iconv -l
elenca tutti quelli supportati.
Esempi:
Converti FROM ISO-8859-1
nella codifica attiva nella shell (basata su LC_CTYPE
, che è UTF-8
basata di default), basandosi sull'esempio sopra:
# Converts to UTF-8; output renders correctly as 'voilà'
sed 's/.*/&/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Tieni presente che questa conversione ti consente di abbinare correttamente i caratteri stranieri :
# Correctly matches 'à' and replaces it with 'ü': -> 'voilü'
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Per convertire l'input BACK in ISO-8859-1
dopo l'elaborazione, è sufficiente reindirizzare il risultato a un altro iconv
comando:
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')" | iconv -t ISO-8859-1