Кодирование перевода строки в текстовых файлах

  • При развитии компьютеров возникла необходимость стандартизации формата хранения и отображения текстовых файлов, чтобы с текстом, составленным в компьютере одного производителя, можно было работать на компьютере другого производителя без необходимости какого-либо преобразования. Для этого в 1963 году была разработана стандартная таблица ASCII, определяющая, как должны кодироваться буквы английского языка, цифры, некоторые другие символы (+%,@$…), а также ряд управляющих символов, не имеющих графического представления и служащих для управления выводом.
  • Первоначально таблица описывала 127 символов, позже была расширена до 255 символов (для хранения используются 8 бит). Коды символов из таблицы ASCII принято записывать в 16-ричном виде, например, латинская буква 'A' кодируется 10-тичным числом '65', которое в 16-ричном виде записывается как '0x41'.
  • Следует подчеркнуть, что в то время еще не существовало графических интерфейсов для взаимодействия с компьютером. Вместо этого в качестве интерактивных терминалов для взаимодействия оператора и ЭВМ использовались "телетайпы" (teletype), представляющие что-то вроде электромеханических печатающих машин, в которых вывод осуществлялся печатью на бумагу (или, в более поздних моделях, отображением на текстовый дисплей). И управляющие символы из состава таблицы ASCII отражают специфику управления такими устройствами. Например:
    • Символ с кодом '0x07' (bell) ничего не печатает, вместо этого воспроизводится звуковой сигнал для привлечения внимания оператора.
    • Символ с кодом '0x08' (backspace) означает 'вернуть печатающую головку на одну позицию назад'. Это, в частности, позволяло печатать несколько символов поверх друг-друга и реализовывать жирный или подчёркнутый шрифт.
    • Символ с кодом '0x0A' (line feed) означает 'перевести строку', т.е. сдвинуть печатающую головку на 1 строку вниз.
    • Символ с кодом '0x0С' (form feed) заставляет принтер завершить печать на используемом листе бумаги, промотать этот лист и дальнейшую печать продолжать на следующем листе.
    • Символ с кодом '0x0D' (carriage return) означает 'возврат каретки', т.е. возвращает курсор или головку в начало текущей строки (без перевода строки)
  • Однако полной стандартизации не получилось и так исторически сложилось, что в операционных системах разных семейств перевод строки в текстовом файле кодируется разными последовательностями управляющих символов ASCII:
    • Для семейств Unix / Linux / BSD / Solaris / … перевод строки кодируется одним символом с кодом '0x0A'. Видимо, подразумевается, что возврат на начало строки при этом происходит по умолчанию.
    • Для семейств DOS и Windows перевод строки кодируется двумя последовательными символами с 16-ричными кодами '0x0D' и '0x0A'.
    • Для семейства Macintosh до версии 9.0 - одним символом с кодом '0x0D'.
    • Для семейства Macintosh после версии MacOS X - одним символом с кодом '0x0A'.
  • :!: В результате текстовый файл, составленный в ОС семейства Windows и скопированный на интерфейсный сервер, может содержать лишние символы с кодом '0x0D', которые в некоторых ситуациях приведут к ошибкам при его обработке.
  • Если такие символы присутствуют в скрипте для qsub, то попытка его запуска планировщиком завершится ошибкой следующего вида:
    -bash: /var/spool/PBS/mom_priv/jobs/XXXXXX.vm-pbs.SC: /bin/bash^M: bad interpreter: No such file or directory

    Дело в том, что вместо интерпретатора '/bin/bash', указанного в самой первой строке скрипта, получился '/bin/bash^M', а такого файла не существует (о чём и говорит фраза 'No such file or directory')

  • Управляющие символы внутри текстового файла можно увидеть, например, из Midnight Commanger, встав на файл курсором и затем:
    • или нажав F4 (редактирование файла). Если в тексте присутствуют символы с кодом '0x0D', они будут отображаться в конце строки как '^M'
    • или нажав F3 (просмотр файла), а затем F4 (отображение в 16-ричном виде).
  • Удалить все такие лишние символы '0x0D' можно или вручную из mc, или выполнив на интерфейсном сервере утилиту 'dos2unix', которой в качестве параметра сообщается имя файла, который необходимо преобразовать (будет модифицирован сам исходный файл, без создания нового файла или резервной копии):
    dos2unix submit.sh

    Существует и аналогичная утилита с именем 'unix2dos', осуществляющая преобразование в обратную сторону (добавляя '0x0D' перед каждым '0x0A').

  • Кроме того, многие программы для передачи файлов умеют сами преобразовывать передаваемые файлы, автоматически добавляя или удаляя символы перевода строки. Например, WinSCP так поступает по умолчанию, если передаваемый файл имеет определённые расширения (txt, html, …), но расширение 'sh' в их состав не входит. Нужно или каждый раз при пересылке текстового файла переключать режим передачи в Text, или зайти в настройки и добавить нужные расширения.
  • Либо, чтобы исключить необходимость перекодирования, создавать и редактировать текстовые файлы можно непосредственно на интерфейсном сервере.