我试图在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打印非法字节序列的位置吗?有人知道非法字节序列是什么吗?
有人知道如何让sed打印非法字节序列的位置吗?有人知道非法字节序列是什么吗?
$ uname -a
Darwin Adams-iMac 18.7.0 Darwin Kernel Version 18.7.0: Tue Aug 20 16:57:14 PDT 2019; root:xnu-4903.271.2~2/RELEASE_X86_64 x86_64
我通过使用tr来回答上面的问题。
我有一个.csv文件,这是一个信用卡对账单,我试图将其导入Gnucash。我住在瑞士,所以我必须处理Zürich这样的单词。怀疑Gnucash不喜欢数字字段中的“”,我决定简单地替换所有
; ;
with
;;
是:
$ head -3 Auswertungen.csv | tail -1 | sed -e 's/; ;/;;/g'
sed: RE error: illegal byte sequence
我用od来说明:注意这个od -c输出的中间部分的374
$ head -3 Auswertungen.csv | tail -1 | od -c
0000000 1 6 8 7 9 6 1 9 7 1 2 2 ; 5
0000020 4 6 8 8 7 X X X X X X 2 6
0000040 6 0 ; M Y N A M E I S X ; 1
0000060 4 . 0 2 . 2 0 1 9 ; 9 5 5 2 -
0000100 M i t a r b e i t e r r e s t
0000120 Z 374 r i c h
0000140 C H E ; R e s t a u r a n t s ,
0000160 B a r s ; 6 . 2 0 ; C H F ;
0000200 ; C H F ; 6 . 2 0 ; ; 1 5 . 0
0000220 2 . 2 0 1 9 \n
0000227
然后我想我可以尝试说服tr用374代替正确的字节码。所以首先我尝试了一些简单的东西,它没有工作,但有一个副作用,显示我麻烦的字节在哪里:
$ head -3 Auswertungen.csv | tail -1 | tr . . ; echo
tr: Illegal byte sequence
1687 9619 7122;5468 87XX XXXX 2660;MY NAME ISX;14.02.2019;9552 - Mitarbeiterrest Z
你可以在374字符处看到tr。
使用perl似乎可以避免这个问题
$ head -3 Auswertungen.csv | tail -1 | perl -pne 's/; ;/;;/g'
1687 9619 7122;5468 87XX XXXX 2660;ADAM NEALIS;14.02.2019;9552 - Mitarbeiterrest Z?rich CHE;Restaurants, Bars;6.20;CHF;;CHF;6.20;;15.02.2019
mklement0的答案很好,但我有一些小调整。
It seems like a good idea to explicitly specify bash's encoding when using iconv. Also, we should prepend a byte-order mark (even though the unicode standard doesn't recommend it) because there can be legitimate confusions between UTF-8 and ASCII without a byte-order mark. Unfortunately, iconv doesn't prepend a byte-order mark when you explicitly specify an endianness (UTF-16BE or UTF-16LE), so we need to use UTF-16, which uses platform-specific endianness, and then use file --mime-encoding to discover the true endianness iconv used.
(我把所有的编码都大写,因为当你用iconv -l列出所有iconv支持的编码时,它们都是大写的。)
# Find out MY_FILE's encoding
# We'll convert back to this at the end
FILE_ENCODING="$( file --brief --mime-encoding MY_FILE )"
# Find out bash's encoding, with which we should encode
# MY_FILE so sed doesn't fail with
# sed: RE error: illegal byte sequence
BASH_ENCODING="$( locale charmap | tr [:lower:] [:upper:] )"
# Convert to UTF-16 (unknown endianness) so iconv ensures
# we have a byte-order mark
iconv -f "$FILE_ENCODING" -t UTF-16 MY_FILE > MY_FILE.utf16_encoding
# Whether we're using UTF-16BE or UTF-16LE
UTF16_ENCODING="$( file --brief --mime-encoding MY_FILE.utf16_encoding )"
# Now we can use MY_FILE.bash_encoding with sed
iconv -f "$UTF16_ENCODING" -t "$BASH_ENCODING" MY_FILE.utf16_encoding > MY_FILE.bash_encoding
# sed!
sed 's/.*/&/' MY_FILE.bash_encoding > MY_FILE_SEDDED.bash_encoding
# now convert MY_FILE_SEDDED.bash_encoding back to its original encoding
iconv -f "$BASH_ENCODING" -t "$FILE_ENCODING" MY_FILE_SEDDED.bash_encoding > MY_FILE_SEDDED
# Now MY_FILE_SEDDED has been processed by sed, and is in the same encoding as MY_FILE