A sample command that exhibits the symptom: sed 's/./@/' <<<$'\xfc'
fails, because byte 0xfc
is not a valid UTF-8 char.
Note that, by contrast, GNU sed
(Linux, but also installable on macOS) simply passes the invalid byte through, without reporting an error.
使用以前接受的答案 https://stackoverflow.com/a/19770395/45375如果您不介意失去对您的真实语言环境的支持,这是一个选项(如果您使用的是美国系统并且您从不需要处理外来字符,那可能没问题。)
但是,那可以达到同样的效果ad-hoc for a 单一命令 only:
LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
注意:重要的是有效的 LC_CTYPE
的设定C
, so LC_CTYPE=C sed ...
would normally也有效,但如果LC_ALL
碰巧被设置(除了C
),它将覆盖个人LC_*
- 类别变量,例如LC_CTYPE
。因此,最稳健的方法是设置LC_ALL
.
然而,(有效地)设置LC_CTYPE
to C
处理字符串就好像每个字节都是它自己的字符 (no执行基于编码规则的解释),其中不考虑对于 - 多字节按需 -UTF-8编码OS X 默认情况下使用的,其中外文字符 have 多字节编码.
简而言之:setting LC_CTYPE
to C
导致 shell 和实用程序仅将基本英文字母识别为字母(7 位 ASCII 范围内的字母),以便外国字符。不会被视为信件,例如导致大写/小写转换失败。
再说一次,如果你不需要的话,这可能没问题match多字节编码字符,例如é
,并且只是想传递这些字符.
如果这还不够和/或您想要了解原因原始错误的信息(包括确定导致问题的输入字节)以及执行编码转换一经请求,read on below.
问题是输入文件的编码与 shell 的编码不匹配。
进一步来说,输入文件包含以 UTF-8 无效方式编码的字符(正如 @Klas Lindbäck 在评论中所说) - 这就是sed
错误消息试图通过invalid byte sequence
.
最有可能的是,您的输入文件使用单字节8位编码例如ISO-8859-1
,经常用于编码“西欧”语言。
Example:
带重音的字母à
有 Unicode 代码点0xE0
(224) - 与中相同ISO-8859-1
。然而,由于性质UTF-8编码,这个单个代码点表示为2字节 -0xC3 0xA0
,而试图通过单字节 0xE0
is invalid在 UTF-8 下。
这是一个问题的演示使用字符串voilà
编码为ISO-8859-1
,与à
表示为one字节(通过 ANSI-C 引用的 bash 字符串 ($'...'
)使用\x{e0}
创建字节):
请注意,sed
命令实际上是一个无操作,只是简单地传递输入,但我们需要它来引发错误:
# -> 'illegal byte sequence': byte 0xE0 is not a valid char.
sed 's/.*/&/' <<<$'voil\x{e0}'
简单来说ignore问题, 以上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 多字节序列 - 需要更复杂的方法来专门识别无效的 UTF-8 字节。)
按需执行编码转换:
标准实用程序iconv
可用于转换为 (-t
) 和/或来自 (-f
) 编码;iconv -l
列出所有支持的。
例子:
转换自ISO-8859-1
到 shell 中有效的编码(基于LC_CTYPE
,即UTF-8
-默认情况下基于),基于上面的示例:
# 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