Аналогичную ситуацию мы имеем и с символом табуляции: при вводе он отражается на терминале и посылается программе, осуществляющей ввод; при выводе символ табуляции просто передается на терминал и интерпретируется. Однако в отличие от предыдущего случая здесь можно указать ядру, что вы хотите получить интерпретацию табуляции при выводе; тогда вместо изображения каждого символа табуляции будет выдаваться нужное число пробелов, чтобы перейти к следующей позиции табуляции. Позиции табуляции установлены в столбцах 9, 17, 25 и т.д. Команда
$ stty = tabs
приводит к замене символов табуляции пробелами при выводе на терминал см. описание stty(1)
.
Обработка символа
Подход системы UNIX к представлению управляющей информации нетрадиционен, особенно использование символа перевода строки для завершения строки (в качестве конца посылки). Многие системы вместо этого трактуют каждую строку как "запись", содержащую не только введенные данные, но и счетчик числа символов в строке (специального символа конца строки нет). В других системах каждая строка завершается символами возврата каретки и перевода строки, поскольку такая последовательность необходима для вывода на большинство терминалов. (Слово "linefeed" завершение строки, синоним перевода строки, поэтому такую последовательность часто называют "CRLF", что невозможно произнести.)
Система UNIX не делает ни того, ни другого: нет записей и счетчиков, к тому же ни в одном файле нет никаких байтов, которые бы вы или ваша программа не поместили туда. Символ перевода строки преобразуется в два символа возврата каретки и перевода строки при выводе на терминал, но программы должны иметь дело с одним символом перевода строки, поскольку это все, что они могут "увидеть". В большинстве случаев подобная простая схема является оптимальной. Если необходима более сложная структура, ее легко построить на базе этой, тогда как получить простое из сложного значительно трудней.
Поскольку завершение строки обозначается символом перевода строки, можно ожидать, что и файл завершается другим специальным символом, скажем \е
как сокращение "end of file" конец файла. Но, посмотрев на вывод программы od
, вы не увидите никакого специального символа в конце файла он просто кончается. Вместо того чтобы использовать специальный символ, система отмечает конец файла сообщением о том, что данных в файле больше нет. Ядро запоминает длину файла, поэтому программа встречает конец файла после обработки всех составляющих файл байтов.
Программы выбирают данные из файла с помощью системного обращения с именем read
(подпрограмма в ядре). При каждом обращении к read
читается следующая часть файла, например очередная введенная строка. Подпрограмма read
также сообщает число прочитанных байтов файла, поэтому конец файла обнаруживается, когда она сообщает: "прочитано 0 байт". Если какие-либо байты оставались в файле, то подпрограмма read
выдала хотя бы часть их. На самом деле, отказ от ввода байта со специальным значением "конец файла" вполне оправдан, поскольку, как отмечалось ранее, смысл содержимого байта зависит от интерпретации файла. Но все файлы имеют конец, и поэтому их следует читать с помощью подпрограммы read
, а возврат нуля это зависящий от интерпретации способ представления конца файла без использования специальных символов.
Когда программа читает с вашего терминала, каждая введенная строка передается программе ядром только после ввода символа перевода строки (т.е. нажатия
Можно посмотреть ввод по строкам на примере команды cat
. Эта команда обычно накапливает или буферизует свой выходной поток, чтобы для повышения эффективности писать большими порциями, но флаг -u
отключает буферизацию, так что она выдает строку сразу по получении:
$ cat
Выдача команды cat с буферизацией
123
456
789
ctl-d
123
456
789
$ cat -u
Выдача команды cat без буферизации
123
123
456
456
789
789
ctl-d
$
Команда cat
получает каждую строку, когда вы нажимаете клавишу
Теперь попробуем сделать нечто другое: введите несколько символов, а затем вместо
$ cat -u 123ctl-d123