Как создать не-ASCII файл с помощью перенаправления с `sh -c`?
Та же команда: 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
символ - кириллическое маленькое письмо 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'
Обновить
Второй байт '\201'
из 'с'
символ в кодировке utf-8-127
как подписанный символ (или 129
в качестве знака без знака) в C.
Поиск по исходному коду (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
escape-байт удален. На 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:
}
Неясно, будут ли эти изменения включены в dash 0.5.6.1
на Ubuntu.
На данный момент единственный способ сделать команду:
$ sh -c 'echo 1 >fсf.dash' && ls *.dash | od -c | grep 201
работать - это перенастроить sh
вернуться к bash
:
$ sudo dpkg-reconfigure dash
Есть ли другие альтернативы?
1 ответ
Из нескольких оболочек (или версий), которые я пробовал, отказали только Dash и Busybox Ash.
$ for sh in bash2.05b bash3.2 bash4.0 bash4.1 bash4.2 dash zsh ksh pdksh mksh ash; do $sh -c 'locale > с.$0'; done
$ csh -c 'locale > с.csh'
$ fish -c 'locale > с.fish'
$ ls -1
?.ash
?.dash
с.bash2.05b
с.bash3.2
с.bash4.0
с.bash4.1
с.bash4.2
с.csh
с.fish
с.ksh
с.mksh
с.pdksh
с.zsh
Содержание было все то же самое.
От man dash
:
В эту оболочку включены только функции, обозначенные POSIX, а также несколько расширений Berkeley. Эта страница руководства не предназначена для обучения или полной спецификации оболочки.
POSIX говорит:
Языковой стандарт POSIX содержит символы в переносимом наборе символов, свойства которого перечислены в LC_CTYPE . В других локалях наличие, значение и представление любых дополнительных символов зависят от локали.
а также
Коды широких символов для других символов определяются локалью и реализацией. ... POSIX.1-2008 не предоставляет средств для определения набора широких символов.