Perintah sampel yang menunjukkan gejala: sed 's/./@/' <<<$'\xfc'
gagal, karena byte 0xfc
bukan karakter UTF-8 yang valid.
Perhatikan bahwa, sebaliknya, GNU sed
(Linux, tetapi juga dapat diinstal pada macOS) cukup melewati byte yang tidak valid, tanpa melaporkan kesalahan.
Menggunakan jawaban yang sebelumnya diterima adalah pilihan jika Anda tidak keberatan kehilangan dukungan untuk lokal Anda yang sebenarnya (jika Anda menggunakan sistem AS dan Anda tidak perlu berurusan dengan karakter asing, itu mungkin baik-baik saja.)
Namun, efek yang sama dapat memiliki ad-hoc untuk perintah tunggal hanya :
LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
Catatan: Yang penting adalah efektif LC_CTYPE
pengaturan C
, sehingga LC_CTYPE=C sed ...
akan normal juga bekerja, tetapi jika LC_ALL
terjadi menjadi set (untuk sesuatu yang lain dari C
), itu akan menimpa individu LC_*
variabel -Kategori seperti LC_CTYPE
. Dengan demikian, pendekatan yang paling kuat adalah menetapkanLC_ALL
.
Namun, pengaturan (efektif) LC_CTYPE
untuk C
memperlakukan string seolah-olah setiap byte adalah karakternya sendiri ( tidak ada interpretasi berdasarkan aturan pengkodean dilakukan), tanpa memperhatikan - multibyte-on-demand - pengkodean UTF-8 yang OS X mempekerjakan secara default , di mana karakter asing memiliki penyandian multibyte .
Singkatnya: pengaturan LC_CTYPE
untukC
penyebab shell dan utilitas hanya mengenal huruf dasar bahasa Inggris sebagai huruf (yang di kisaran ASCII 7-bit), sehingga karakter asing. tidak akan diperlakukan sebagai huruf , menyebabkan, misalnya, konversi huruf besar / kecil gagal.
Sekali lagi, ini mungkin baik-baik saja jika Anda tidak perlu mencocokkan karakter multibyte-encoded seperti é
, dan hanya ingin melewati karakter tersebut .
Jika ini tidak cukup dan / atau Anda ingin memahami penyebab kesalahan asli (termasuk menentukan byte input apa yang menyebabkan masalah) dan melakukan pengkodean konversi sesuai permintaan, baca terus di bawah ini.
Masalahnya adalah bahwa pengkodean file input tidak cocok dengan shell.
Lebih khusus lagi, file input berisi karakter yang dikodekan dengan cara yang tidak valid di UTF-8 (seperti yang dinyatakan oleh @Klas Lindbäck dalam komentar) - itulah yang ingin disampaikan oleh sed
pesan kesalahan invalid byte sequence
.
Kemungkinan besar, file input Anda menggunakan pengodean 8-bit single-byte sepertiISO-8859-1
, yang sering digunakan untuk menyandikan bahasa "Eropa Barat".
Contoh:
Huruf beraksen à
memiliki Unicode codepoint 0xE0
(224) - sama seperti pada ISO-8859-1
. Namun, karena sifat dari UTF-8 encoding, codepoint tunggal ini diwakili sebagai 2 byte - 0xC3 0xA0
, sedangkan mencoba untuk melewati byte tunggal 0xE0
adalah tidak valid di bawah UTF-8.
Berikut ini demonstrasi masalah menggunakan string yang voilà
disandikan sebagai ISO-8859-1
, dengan yang à
direpresentasikan sebagai satu byte (melalui string bash yang dikutip ANSI-C $'...'
) yang menggunakan\x{e0}
untuk membuat byte):
Perhatikan bahwa sed
perintah ini efektif no-op yang hanya melewati input, tetapi kita perlu memprovokasi kesalahan:
# -> 'illegal byte sequence': byte 0xE0 is not a valid char.
sed 's/.*/&/' <<<$'voil\x{e0}'
Untuk mengabaikan masalah , LCTYPE=C
pendekatan di atas dapat digunakan:
# No error, bytes are passed through ('á' will render as '?', though).
LC_CTYPE=C sed 's/.*/&/' <<<$'voil\x{e0}'
Jika Anda ingin menentukan bagian input mana yang menyebabkan masalah , coba yang berikut ini:
# 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}'
Output akan menampilkan semua byte yang memiliki set bit tinggi (byte yang melebihi kisaran ASCII 7-bit) dalam bentuk heksadesimal. (Namun, perlu diketahui bahwa itu juga mencakup urutan multibyte UTF-8 yang dikodekan dengan benar - diperlukan pendekatan yang lebih canggih untuk secara spesifik mengidentifikasi byte yang tidak valid dalam UTF-8.)
Melakukan konversi pengkodean sesuai permintaan :
Utilitas standar iconv
dapat digunakan untuk mengkonversi ke ( -t
) dan / atau dari ( -f
) pengkodean;iconv -l
daftar semua yang didukung.
Contoh:
Konversi FROM ISO-8859-1
ke pengkodean yang berlaku di shell (berdasarkan LC_CTYPE
, yang UTF-8
-berdasarkan secara default), membangun contoh di atas:
# Converts to UTF-8; output renders correctly as 'voilà'
sed 's/.*/&/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Perhatikan bahwa konversi ini memungkinkan Anda untuk mencocokkan karakter asing dengan benar :
# Correctly matches 'à' and replaces it with 'ü': -> 'voilü'
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Untuk mengonversi input BACK ke ISO-8859-1
setelah diproses, cukup pipa hasilnya ke iconv
perintah lain :
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')" | iconv -t ISO-8859-1