Пример команды, которая демонстрирует симптом: sed 's/./@/' <<<$'\xfc'
терпит неудачу, потому что байт 0xfc
не является допустимым символом UTF-8.
Обратите внимание, что, напротив, GNU sed
(Linux, но также устанавливается на macOS) просто пропускает недействительный байт, не сообщая об ошибке.
Использование ранее принятого ответа - вариант, если вы не против потерять поддержку своего истинного языка (если вы работаете в системе США и вам никогда не нужно иметь дело с иностранными символами, это может быть хорошо).
Однако тот же эффект можно получить Ad-Hoc для одной команды только :
LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
Примечание: важен эффективный LC_CTYPE
параметр C
, поэтому LC_CTYPE=C sed ...
он также обычно работает, но если LC_ALL
он установлен (что-то иное, чем C
), он переопределит отдельные LC_*
переменные -категории, такие как LC_CTYPE
. Таким образом, наиболее надежный подход заключается в установке LC_ALL
.
Тем не менее, (фактически) настройки LC_CTYPE
для C
обрабатывают строки , как если бы каждый байт был свой характер ( не интерпретации , основанная на правилах кодирования выполняется), причем без учета для - многобайтового по требованию - UTF-8 , кодирующие , что OS X использует по умолчанию где иностранные символы имеют многобайтовые кодировки .
В двух словах: заходящих LC_CTYPE
наC
причины оболочку и утилиты только распознавать основные английские буквы как буквы (те , в 7-битном диапазоне ASCII), так что иностранные гольцы. не будут рассматриваться как буквы , что приведет, например, к неудачному преобразованию в верхний / нижний регистр.
Опять же, это может быть хорошо, если вам не нужно сопоставлять многобайтовые символы, такие как é
, и просто хотите пропустить такие символы .
Если этого недостаточно и / или вы хотите понять причину исходной ошибки (включая определение того, какие входные байты вызвали проблему) и выполнить преобразования кодирования по требованию, читайте далее.
Проблема в том, что кодировка входного файла не совпадает с кодировкой оболочки.
В частности, входной файл содержит символы, закодированные таким образом, который недопустим в UTF-8 (как @Klas Lindbäck заявил в комментарии) - вот что sed
пытается сказать сообщение об ошибке invalid byte sequence
.
Скорее всего, ваш входной файл использует однобайтовую 8-битную кодировку, например ISO-8859-1
, часто используемую для кодирования "западноевропейских" языков.
Пример:
Буква с акцентом à
имеет код Unicode 0xE0
(224) - такой же, как и в ISO-8859-1
. Однако из - за характера UTF-8 кодировке, этот единственный элемент кода представлен в виде 2 -х байт - 0xC3 0xA0
, в то время как пытается передать один байт 0xE0
является недействительным в соответствии с UTF-8.
Вот демонстрация проблемы с использованием строки, voilà
закодированной как ISO-8859-1
, с à
представленным в виде одного байта (через строку bash в кавычках ANSI-C ( $'...'
), которая используется \x{e0}
для создания байта):
Обратите внимание, что эта sed
команда по сути является no-op, которая просто пропускает ввод, но она нам нужна, чтобы вызвать ошибку:
# -> 'illegal byte sequence': byte 0xE0 is not a valid char.
sed 's/.*/&/' <<<$'voil\x{e0}'
Чтобы просто игнорировать проблему , LCTYPE=C
можно использовать вышеуказанный подход:
# No error, bytes are passed through ('á' will render as '?', though).
LC_CTYPE=C sed 's/.*/&/' <<<$'voil\x{e0}'
Если вы хотите определить, какие части ввода вызывают проблему , попробуйте следующее:
# 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}'
Вывод покажет вам все байты с установленным старшим битом (байты, которые превышают 7-битный диапазон ASCII) в шестнадцатеричной форме. (Тем не менее, обратите внимание, что это также включает в себя правильно закодированные многобайтовые последовательности UTF-8 - для более точной идентификации байтов invalid-in-UTF-8 потребуется более сложный подход.)
Выполнение кодирования преобразований по требованию :
Стандартная утилита iconv
может использоваться для преобразования в ( -t
) и / или из ( -f
) кодировок; iconv -l
перечисляет все поддерживаемые.
Примеры:
Преобразование FROM ISO-8859-1
в действующую кодировку в оболочке (на основе LC_CTYPE
, которая UTF-8
по умолчанию -base), основываясь на приведенном выше примере:
# Converts to UTF-8; output renders correctly as 'voilà'
sed 's/.*/&/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Обратите внимание, что это преобразование позволяет вам правильно сопоставлять иностранные символы :
# Correctly matches 'à' and replaces it with 'ü': -> 'voilü'
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
Чтобы преобразовать ввод BACK ISO-8859-1
после обработки, просто передайте результат в другую iconv
команду:
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')" | iconv -t ISO-8859-1