#pragma css /css/2018.css
<<BI>>

= Комментарии к практикуму 8 =

== Кодировка файлов скриптов ==

=== Узнать кодировку файла ===

Проверить кодировку файла можно с помощью команды `file`. Главная функция этой команды -- угадать тип файла по его содержимому, но она умеет определять и основные типы кодировок. Чтобы показать, в том числе, кодировку, есть опция `-i`, чтобы показать только кодировку тоже есть опция (`--mime-encoding`), но её сложнее набирать.

В случае кодировки UTF-8 будет написано "charset=utf-8", или "charset=us-ascii", если в вашем файле только символы из первой половины кодовой таблицы ASCII (т.е., только цифры, английские буквы, простые знаки препинания, пробельные символы и еще кое-что, более менее все, что можно найти на клавиатуре в английской раскладке), которые в UTF-8 кодируются так же, как в ASCII.

В случае, CP1251 (она же Windows-1251 и ANSI по версии Far, стандартная 8-битная кодировка для русского языка в Windows), CP866 (устаревшая 8-битная кодировка для русского языка в Windows), KOI8-R (устаревшая 8-битная кодировка для русского языка в Unix-подобных операционных системах) будет напечатано "charset=iso-8859-1" (`file` не умеет различать почти никакие 8-битные ASCII-совместимые кодировки).

Если вам вдруг все-таки надо точно определить кодировку файла, можете использовать команду `chardet`.

=== Как поменять кодировку файла ===

Для изменения кодировки текстовых файлов существует команда `iconv`. Стандартный способ запуска следующий:
{{{#!highlight bash
iconv -f FROM -t TO OLD_FILE | less # чтобы убедиться, что смена кодировки происходит удачно
iconv -f FROM -t TO OLD_FILE > NEW_FILE # чтобы сохранить перекодированный текст в файл NEW_FILE
}}}
`FROM` и `TO` -- названия кодировок, которые понимает `iconv`, а OLD_FILE и NEW_FILE -- имена файлов. Полный список всех поддерживаемых названий кодировок можно узнать с помощью опции `-l`:  
{{{#!highlight bash
iconv -l | less # список длинный!
}}}
В вашем случае команда почти наверняка будет следующая:
{{{#!highlight bash
iconv -f cp1251 -t utf8 OLD_FILE > NEW_FILE
}}}

=== Проблемы с UTF-8 (BOM) ===

С кодировкой UTF-8 есть некоторая подстава, про которую я каждый раз забываю рассказать. Эта кодировка допускает в самом начале файла присутствие так называемого BOM (byte order mark) -- специального символа Unicode, который в случае UTF-8 кодируется тремя байтами 0xEF 0xBB 0xBF. BOM не является обязательным или даже рекомендуемым для UTF-8, но некоторые программы его добавляют при сохранении файла в кодировке UTF-8. Например, Far поступает именно так, и не только Far.

Все программы, которые умеют понимать UTF-8, обычно правильно обрабатывают этот символ и просто игнорируют его при отображении текста. Но с шебангом (#!) начинаются проблемы. Как я вам говорил, символы #! должны быть в самом начале файла, иначе они не работают, в том числе, если перед ними стоит BOM, который ещё и не отображается в текстовом редакторе.

Выход простой -- удалить BOM. Но проще сказать, чем сделать. Для начала надо убедиться, что он действительно есть. Самый простой способ -- посмотреть файл в `less`. Если в начале файла есть BOM, то он будет отображаться в виде <U+FEFF> в начале первой строки.

Теперь вам надо удалить первый символ или 3 первых байта (в этом случае). Это можно сделать кучей разных способов. Например, с помощью sed:
{{{#!highlight bash
sed -Ei '1s/^.//' FILE # -i для изменения файла "на месте", используйте с осторожностью!
# 1 - адрес первой строки
# s/^.// - удаление любого первого символа в строке
}}}
На самом деле, в случае скриптов, начинающихся с #!, можно использовать следующую команду, независимо от того, был в начале BOM, или нет:
{{{#!highlight bash
sed -Ei '1s/^[^#]*#/#/' FILE # -i для изменения файла "на месте", используйте с осторожностью!
# 1 - адрес первой строки
# s/^[^#]*#/#/ - удаление любого количества любых символов до первого символа #
}}}

== Кодировка переносов строк ==

Существует всего два распространенных способа кодировать переносы строк в текстовых файлах: стиль Windows и стиль  Unix. Как не сложно догадаться, почти все программы в Linux ожидают переносы строк в стиле Unix.

В Windows переносы строк кодируются двумя символами CR (возврат каретки) и LF (перевод строки). В Unix -- одним символом LF. Самый простой способ привести файл к Unix формату -- просто удалить из него всего символы CR вообще, если они есть. Для этого можно использовать команду `tr -d`.
{{{#!highlight bash
cat OLD_FILE | tr -d "\r" > NEW_FILE # \r распространенное обозначение CR, \n -- LF, \t -- TAB
# OLD_FILE и NEW_FILE должны быть разными файлами! Иначе потеряете все содержимое.
# или
tr -d "\r" < OLD_FILE > NEW_FILE
}}}

Проверить наличие CR в файле можно с помощью:
{{{#!highlight bash
less -U FILE # отображает CR как ^M и TAB на ^I
cat -A FILE | less # cat -A меняет CR на ^M, LF на $ и TAB на ^I
}}}