我试图在Mac OS X上替换Makefile中的字符串,以便交叉编译到iOS。该字符串嵌入了双引号。命令是:
sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
错误是:
sed: RE error: illegal byte sequence
我试过转义双引号、逗号、破折号和冒号,但没有成功。例如:
sed -i "" 's|\"iphoneos-cross\"\,\"llvm-gcc\:\-O3|\"iphoneos-cross\"\,\"clang\:\-Os|g' Configure
我花了很长时间调试这个问题。有人知道如何让sed
打印非法字节序列的位置吗?或者有人知道非法字节序列是什么吗?
8条答案
按热度按时间j13ufse21#
显示以下症状的示例命令:
sed 's/./@/' <<<$'\xfc'
失败,因为字节0xfc
不是有效的UTF-8字符。请注意,相比之下,* GNU *
sed
(Linux,但也可安装在macOS上)只是通过无效字节,而不报告错误。如果你不介意失去对你的真实语言环境的支持,那么使用**formerly accepted answer是一个选择**(如果你在美国的系统上,你永远不需要处理外来字符,那可能是好的。)
但是,仅***************************************************************************************************************************************************************************************************************************************************
注意:重要的是
C
的 * effective *LC_CTYPE
设置,所以LC_CTYPE=C sed ...
* 通常 * 也可以工作,但是如果LC_ALL
碰巧被设置(设置为C
以外的值),它将覆盖单个LC_*
-类别变量,如LC_CTYPE
。因此,最可靠的方法是设置LC_ALL
。但是,(有效地)将
LC_CTYPE
设置为C
会将字符串视为每个字节都是其自己的字符(* 不执行 * 基于编码规则的解释),不考虑OS X默认使用的-multibyte-on-demand-UTF-8编码,其中外来字符具有多字节编码。简而言之:* * 将
LC_CTYPE
设置为C
会导致shell和实用程序仅将基本英文字母识别为字母(7位ASCII范围内的字母),因此外来字符不会被视为字母**,从而导致大写/小写转换失败。同样,如果您不需要 * 匹配 * 多字节编码的字符(如
é
),而只是想 * 传递这些字符 *,这可能是很好的。如果这还不够,并且/或者您想要了解原始错误的原因(包括确定导致问题的输入字节)并按需执行编码转换,请阅读下面的。
问题是输入文件的编码与shell的不匹配。
更具体地说,输入文件包含以UTF-8无效的方式编码的字符(正如@Klas Lindbäck在评论中所说的那样)-这就是
sed
错误消息invalid byte sequence
试图说的。最有可能的是,您的输入文件使用单字节8位编码,例如
ISO-8859-1
,通常用于编码“西欧”语言。重音字母
à
的Unicode代码点为0xE0
(224)-与ISO-8859-1
相同。然而,由于 * UTF-8 * 编码的性质,这个单个代码点表示为 * 2 * bytes-0xC3 0xA0
,而试图传递 * 单个字节 *0xE0
在UTF-8下是 * 无效 * 的。下面是问题的演示,使用字符串
voilà
编码为ISO-8859-1
,à
表示为 * one * byte(通过ANSI-C引用的bash字符串($'...'
)使用\x{e0}
创建字节):请注意,
sed
命令实际上是一个no-op,它只是简单地传递输入,但我们需要它来引发错误:要简单地*忽略 * 问题,可以使用上面的
LCTYPE=C
方法:如果要确定输入的哪些部分导致问题,请尝试以下操作:
输出将以十六进制形式显示所有高位设置的字节(超过7位ASCII范围的字节)。(但是,请注意,这也包括正确编码的UTF-8多字节序列-需要更复杂的方法来专门识别无效的UTF-8字节。)
标准实用程序
iconv
可用于转换为(-t
)和/或从(-f
)编码;iconv -l
列出了所有支持的。将FROM
ISO-8859-1
转换为shell中有效的编码(基于LC_CTYPE
,默认情况下基于UTF-8
),以上面的示例为基础:请注意,此 * 转换允许您正确匹配外来字符 *:
要在处理后将输入BACK转换为
ISO-8859-1
,只需将结果通过管道传输到另一个iconv
命令:bwntbbo32#
将以下行添加到
~/.bash_profile
或~/.zshrc
文件中。xriantvc3#
我的解决方法是使用Perl:
laawzig24#
您只需在 sed 命令. ex之前通过管道传输 iconv 命令,并输入file.txt:
iconv -f ISO-8859-1 -t UTF8-MAC file.txt|sed 's/something/àéèêçùû/g'|...
注意大小写,网页通常显示小写,如〈charset=iso-8859-1”/〉和 iconv 使用大写。您可以使用命令 iconv -l 在系统中列出 iconv 支持的代码集。
yjghlzjz5#
mklement0's answer很棒,但我有一些小的调整。
在使用
iconv
时,显式指定bash
的编码似乎是个好主意。(even though the unicode standard doesn't recommend it),因为there can be legitimate confusions between UTF-8 and ASCII without a byte-order mark。不幸的是,当您显式指定endianness时,iconv
不会预先添加字节顺序标记(UTF-16BE
或UTF-16LE
),因此我们需要使用UTF-16
,它使用特定于平台的字节序,然后使用file --mime-encoding
来发现使用的真正字节序iconv
。(我把我所有的编码都大写,因为当你用
iconv -l
列出iconv
支持的所有编码时,它们都是大写的。)flmtquvp6#
有人知道如何让sed打印非法字节序列的位置吗?或者有人知道非法字节序列是什么吗?
我通过使用 tr 来回答上述问题。
我有一个.csv文件是一个信用卡对帐单,我试图将其导入Gnucash。我在瑞士,所以我必须处理像Zürich这样的单词。怀疑Gnucash不喜欢数字字段中的“”,我决定简单地替换所有
与
下面是:
我用 od 来表达一些想法:注意这个 od -c 输出中间的374
然后我想我可以尝试说服 tr 用374来代替正确的字节码,所以我首先尝试了一些简单的方法,这不起作用,但有一个副作用,就是告诉我麻烦的字节在哪里:
您可以在374字符处看到 tr bails。
使用Perl似乎可以避免这个问题
8e2ybdfx7#
我的解决方法一直是使用gnu
sed
。对我的目的来说工作得很好。jk9hmnmh8#
对我来说,这个问题的根源在于试图打开/编辑
.DS_Store
文件的命令。删除这些命令为我解决了这个问题。