Обходимо помилки утиліт з пакета GNU Core Utilities

TerminalПакет coreutils предустановлен в багатьох дистрибутивах Linux. Він містить в собі стандартні і такі звичні утиліти, як cat , chmod , date , echo , ls і багато інших. Але навіть у такому канонічному пакеті зустрічаються помилки, які можуть перешкодити роботі користувача. З однією з них я зіткнувся на власному досвіді і хочу розповісти про те, як зміг її обійти.
 
Завдання було наступна — перетворити текстовий файл з довгими рядками так, щоб жодна рядок не була довшою 80 символів. Довгі рядки повинні розбиватися на кілька рядків по 80-менш символів. Файл закодований в UTF-8. Трохи погуглити можна дізнатися, що в Unix-подібних ОС з цим завданням справляється утиліта fold . Дуже добре, значить, будемо її використовувати. Для початку виконаємо в терміналі пару тестових команд, щоб навчитися управлятися з нею. Я наведу нижче висновок команд, виконаних у системі Debian 7.5 з пакетом coreutils 8.13. Такий же висновок буде і в системі Arch Linux з coreutils 8.22.
 
При виконанні всіх тестових команд настройки локалі наступні:
 
 
$ locale
LANG=ru_RU.UTF-8
LC_CTYPE="ru_RU.UTF-8"
LC_NUMERIC="ru_RU.UTF-8"
LC_TIME="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
LC_MONETARY="ru_RU.UTF-8"
LC_MESSAGES="ru_RU.UTF-8"
LC_PAPER="ru_RU.UTF-8"
LC_NAME="ru_RU.UTF-8"
LC_ADDRESS="ru_RU.UTF-8"
LC_TELEPHONE="ru_RU.UTF-8"
LC_MEASUREMENT="ru_RU.UTF-8"
LC_IDENTIFICATION="ru_RU.UTF-8"
LC_ALL=ru_RU.UTF-8

Якщо у вас не так, то виконайте:
 
 
$ export LC_ALL="ru_RU.UTF-8"

Нехай тестова команда розіб'є рядок «abcdefghij» на рядки по 4 символу:
 
 
$ echo "abcdefghij" | fold -w 4
abcd
efgh
ij

Здорово! Тепер рядок «абвгдеежзі»:
 
 
$ echo "абвгдеёжзи" | fold -w 4
аб
вг
де
ёж
зи

І тут-то нас чекає сюрприз. Бачимо, що рядок «абвгдеежзі» розбилася на рядки по два символи. Справа тут в тому, що кириличний символ в кодуванні UTF-8 займає два байти, а символ латиниці один. Утиліта fold , вважаючи всі символи однобайтового, просто розбила цю рядок (масив байт) на шматки по 4 байти. Як видно, такий алгоритм розбиття вірний в кодуванні UTF-8 тільки для латинських символів. Водночас утиліта wc вірно підрахує кількість символів у рядку «абвгдеежзі»:
 
 
$ echo -n "абвгдеёжзи" | wc -m
10

Це говорить про те, що підтримка Unicode в пакеті coreutils реалізована частково, і результат роботи з юнікодом різних утиліт може бути непередбачуваним.
 
Насправді, про цю помилку було відомо кілька років тому. Вона описана тут і тут , і навіть дан відповідь від розробників, але, на жаль, вона як і раніше знаходиться в стані «це не баг, це фіча».
 
Описане вище не відноситься до BSD системам, у них власна реалізація стандартних утиліт. Тест в системі FreeBSD 10 показав, що там з юнікодом все гаразд.
 
Тепер поговоримо про те, як обійти цю помилку. Мені відомі дві заміни coreutils : BusyBox і Heirloom . Перший варіант мені здався більш актуальним і простим, тому покажу як з його допомогою спорудити милицю, який дозволить нормально користуватися утилітою fold у вашій системі. Аналогічним чином можна спорудити милицю і для будь-якої іншої стандартної утиліти.
 
Для початку встановимо пакет busybox . В системі Debian команда:
 
 
# apt-get install busybox

В системі Arch Linux, відповідно, така команда:
 
 
# pacman -S busybox

Згідно документації , використовувати BusyBox можна так:
 
 
$ busybox ls -l
$ busybox ps
$ busybox seq 1 5

Тобто просто передавати ім'я утиліти як параметр виконуваного файлу busybox . Можна також перейменувати виконуваний файл в одну з підтримуваних їм команд, і він буде автоматично діяти так, як ніби це і є ця команда. Перейменовувати ми його не будемо, але от символьне посилання з ім'ям fold на нього створимо:
 
 
# cd $(dirname $(which fold))
# mv fold fold.orig
# ln -s $(which busybox) fold

Після цього fold можна використовувати самим звичним чином: викликати з терміналу або скрипта. Така латочка в системі є для мене прийнятною. Буду радий, якщо комусь вона теж зможе допомогти. А поки залишається сподіватися, що коли-небудь coreutils буде повністю підтримувати юнікод.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.