【发布时间】:2011-07-06 19:37:25
【问题描述】:
相同的命令:echo 1 > filename 创建不同的文件名:
$ sh -c 'echo $LANG >=с=.sh' && ls *.sh | od -c
0000000 = 321 = . s h \n
0000007
和
$ bash -c 'echo $LANG >=с=.bash' && ls *.bash | od -c
0000000 = 321 201 = . b a s h \n
0000012
其中с 是U+0441 字符——CYRILLIC SMALL LETTER ES。很明显sh 吃掉了utf-8 编码中的第二个字节。
$ ls *sh
=?=.sh =с=.bash
$LANG 在这两种情况下都是:
$ cat *sh
en_US.utf8
en_US.utf8
sh 链接到我系统上的dash:
$ apt-cache show dash | grep -i version
Version: 0.5.5.1-7ubuntu1
stty iutf8 已设置。
是否有任何设置允许dash 不破坏多字节字符?
我在手册中没有看到任何关于字符编码的提及:
$ man dash | grep -i encoding
$ man dash | grep -Pi 'multi.*byte'
更新
utf-8 编码中'с' 字符的第二个字节'\201' 是
-127 在 C 中作为有符号字符(或 129 作为无符号字符)。
在源代码 (apt-get source dash) 中搜索 -127 的结果是:
src/parser.h:38:#define CTL_FIRST -127 /* first 'special' character */
src/parser.h:39:#define CTLESC -127 /* escape next character */
搜索CTLESC 会导致rmescapes() 宏导致
来自src/expand.c:expandarg()的以下片段:
/*
* TODO - EXP_REDIR
*/
if (flag & EXP_FULL) {
ifsbreakup(p, &exparg);
*exparg.lastp = NULL;
exparg.lastp = &exparg.list;
expandmeta(exparg.list, flag);
} else {
if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
rmescapes(p);
sp = (struct strlist *)stalloc(sizeof (struct strlist));
sp->text = p;
*exparg.lastp = sp;
exparg.lastp = &sp->next;
}
TODO 和 XXX 暗示更新的版本可能
帮助。 debian/dash.README.source 指向:
$ git clone http://smarden.org/git/dash.git/
$ cd dash
有两个分支:
$ git br
* debian-sid
release+patches
在debian-sid 上,转义字节被删除。在release+patches
分支grep 找到丢失的字节。
$ ./configure
$ make && rm *.dash -f; ./dash -c 'echo 1 >fсf.dash' &&
> ls *.dash | od -c | grep 201
git diff debian-sid...release+patches 表明 rmescapes() 是
在release-patches中删除:
diff --git a/src/expand.c b/src/expand.c
index e4c4c8b..f2f964c 100644
--- a/src/expand.c
+++ b/src/expand.c
...
@@ -213,8 +210,6 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
exparg.lastp = &exparg.list;
expandmeta(exparg.list, flag);
} else {
- if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
- rmescapes(p);
sp = (struct strlist *)stalloc(sizeof (struct strlist));
sp->text = p;
*exparg.lastp = sp;
@@ -412,7 +407,7 @@ lose:
}
尚不清楚这些更改是否会包含在 Ubuntu 上的 dash 0.5.6.1 中。
目前唯一的命令方式:
$ sh -c 'echo 1 >fсf.dash' && ls *.dash | od -c | grep 201
工作是将sh重新配置回bash:
$ sudo dpkg-reconfigure dash
还有其他选择吗?
【问题讨论】:
标签: ubuntu utf-8 debian sh dash-shell