显示症状的示例命令:ISO-8859-1失败,因为字节iconv不是有效的UTF-8字符。
请注意,相比之下,GNU UTF-8(Linux,但也可以在macOS上安装)只是传递无效字节,而不报告错误。
如果您不介意失去对真实语言环境的支持,那么使用之前接受的答案是一种选择(如果您使用的是美国系统而且您永远不需要处理外国字符,那可能没问题。)
但是,对于单个命令,ad-hoc也可以产生相同的效果:
LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
注意:重要的是有效ISO-8859-1设置为iconv,因此UTF-8通常也可以工作,但如果碰巧设置iconv -l(除了\x{e0}之外的其他东西),它将覆盖单个LC_*类别变量,例如LC_CTYPE。因此,最重要的是 健全的方法是设置LC_ALL。
但是,(有效地)将ISO-8859-1设置为iconv将字符串视为每个字节都是其自己的字符(不执行基于编码规则的解释),而不考虑OS X使用的 - 多字节按需 - UTF-8编码 默认情况下,外部字符具有多字节编码。
简而言之:将ISO-8859-1设置为iconv会导致shell和实用程序仅将基本英文字母识别为字母(7位ASCII范围内的字母),以便外部字符。 不会被视为字母,例如导致大写/小写转换失败。
同样,如果您不需要匹配多字节编码的字符(例如ISO-8859-1),并且只是想传递这些字符,这可能会很好。
如果这不够和/或您想了解原始错误的原因(包括确定导致问题的输入字节)并按需执行编码转换,请阅读下文。
问题是输入文件的编码与shell的编码不匹配。
更具体地说,输入文件包含以UTF-8无效的方式编码的字符(如评论中所述@KlasLindbäck) - 这是ISO-8859-1错误消息试图通过iconv说的。
最有可能的是,您的输入文件使用单字节8位编码,例如ISO-8859-1,经常用于编码“西欧”语言。
例:
带有重音的字母ISO-8859-1具有Unicode代码点iconv(224) - 与UTF-8中的相同。但是,由于UTF-8编码的性质,此单个代码点表示为2个字节 - iconv -l,而尝试传递单个字节\x{e0}则 在UTF-8下无效。
以下是使用编码为ISO-8859-1的字符串ISO-8859-1进行演示的示例,其中UTF-8表示为一个字节(通过ANSI-C引用的bash字符串(iconv -l),使用\x{e0}创建字节):
请注意,ISO-8859-1命令实际上是一个简单地传递输入的无操作,但是我们需要它来激发错误:
# -> 'illegal byte sequence': byte 0xE0 is not a valid char.
sed 's/.*/&/' <<
要简单地忽略该问题,可以使用上述ISO-8859-1方法:
# No error, bytes are passed through ('á' will render as '?', though).
LC_CTYPE=C sed 's/.*/&/' <<
如果要确定输入的哪些部分导致问题,请尝试以下操作:
# Convert bytes in the 8-bit range (high bit set) to hex. representation.
# -> 'voil\x{e0}'
iconv -f ASCII --byte-subst='\x{%02x}' <<
输出将以十六进制形式显示所有具有高位设置(超过7位ASCII范围的字节)的字节。 (但是,请注意,还包括正确编码的UTF-8多字节序列 - 需要更复杂的方法来专门识别UTF-8字节中的无效字节。)
按需执行编码转换:
标准效用ISO-8859-1可用于转换(iconv)和/或(UTF-8)编码; iconv -l列出了所有受支持的。
例子:
将shell从ISO-8859-1转换为shell中有效的编码(基于iconv,默认情况下为UTF-8),基于上面的示例:
# Converts to UTF-8; output renders correctly as 'voilà'
sed 's/.*/&/' <<
请注意,此转换允许您正确匹配外来字符:
# Correctly matches 'à' and replaces it with 'ü': -> 'voilü'
sed 's/à/ü/' <<
要在处理后将输入BACK转换为ISO-8859-1,只需将结果传递给另一个iconv命令:
sed 's/à/ü/' <<