Главная » Программирование для UNIX » Файловая система Основы

0

Все,  что ни есть  в системе UNIX, – это файл. И это не такое уж  чрез мерное  упрощение, как может показаться на  первый взгляд. Когда  разрабатывалась первая версия системы, еще до того, как она получила название, было решено сконцентрировать усилия на создании простой  и удобной  в использовании структуры файловой системы. И своему  успеху и удобству применения  UNIX  в  большой степени обязан именно  файловой  системе. Она  представляет  собой один  из  лучших примеров воплощения философии «простоты», показывая, какой мощи  можно достичь  аккуратной реализацией небольшого  количества хорошо продуманных идей.

Чтобы уверенно чувствовать себя  при изучении команд и их  взаимосвязей, необходимо иметь представление об основах структуры и функционирования файловой системы. В этой главе обсуждается большинство аспектов использования файловой системы: что такое файлы, чем они представлены, каталоги и иерархия файловой системы, права доступа, индексные дескрипторы (внутренняя системная запись файлов, inodes) и файлы устройств. Так как практически всегда  использование системы UNIX  связано с обработкой  файлов, существует множество команд для получения информации о файлах и их трансформации; самые употребительные из них представлены в этой главе.

Файл – это последовательность байтов. (Байт – это небольшой фрагмент информации, состоящий из 8 бит. В этой книге под байтом мы будем понимать  эквивалент символа.) Система не  навязывает файлу какую-то определенную структуру и никоим образом не пытается трактовать его

содержание, смысл байтов  зависит только от программ, которые интерпретируют файл. Кроме  того, будет показано, что это утверждение верно не только для дисковых файлов, но и для файлов периферийных устройств. Магнитные ленты, почтовые сообщения, символы, вводи мые с клавиатуры, вывод  принтера, поток данных в программном ка нале  – каждый из этих  файлов представляет собой просто  последовательность байтов  по отношению к системе и ее программам.

Лучший способ изучения файлов – практика, так что давайте начнем с создания небольшого файла:

$ ed a

now is  the  time

for  all  good  people

.

w  junk

36

q

$ ls -l junk

–rw–r––r–– 1 you                   36  Sep 27 06:11  junk

$

Создан  файл junk, в нем 36 байт – 36 символов, которые были  введены с клавиатуры в режиме добавления (естественно, не считая исправлений ошибок ввода). Чтобы просмотреть файл, введите

$ cat  junk

now  is  the  time

for  all  good  people

$

Команда cat показывает, как выглядит файл. Команда od (octal dump – восьмеричный дамп) выводит видимое представление всех байтов файла:

$ od -c  junk

0000000    n     o     w                    i   s             t   h      e             t   i   m         e   \n 0000020    f   o     r             a      l   l       g     o     o     d             p     e      o 0000040    p     l   e   \n

0000044

$

Параметр –c означает «интерпретировать байты как символы». Если  задан параметр –b,  то  будет  показано и восьмеричное представление байтов:1

1        Каждый байт  файла – это число, достаточно большое для  кодирования печатных символов. В большинстве UNIX-систем принята кодировка ASCII, некоторые же  машины, в частности выпущенные IBM, пользуются кодировкой EBCDIC. В этой книге везде подразумевается кодировка ASCII;  введите  cat  /usr/pub/ascii или обратитесь к ascii(7), чтобы  просмотреть восьмеричные значения всех символов.

$ od -cb  junk

0000000    n     o     w                    i   s             t   h      e             t   i   m         e   \n 156 157 167  040 151 163 040 164 150 145 040 164  151  155 145 012

0000020    f   o     r         a     l   l       g     o     o      d             p     e     o

146 157 162 040 141 154 154 040 147  157  157 144 040 160 145 157 0000040    p     l      e      \n

160 154 145   012

0000044

$

Семизначные числа слева  обозначают  местоположение в файле –  порядковый номер  следующего выведенного символа, в  восьмеричной записи. Между прочим, то, что восьмеричным числам придано такое значение, – это наследие PDP-11, для которой предпочтительной была  восьмеричная нотация. Для других машин больше подходит шестнадцатеричная запись – параметр –x позволяет выводить в таком виде.

Обратите внимание,  что  после  каждой строки  встречается символ с восьмеричным значением 012. Это ASCII-символ новой  строки, то есть то, что система помещает в поток  ввода, когда пользователь нажимает клавишу Return. По соглашению, заимствованному из Си, представление символа новой  строки выглядит как \n, но это просто  условность, используемая такими программами, как od, для удобства чтения, на самом  же деле величина, хранимая в файле, – это один байт 012.

Символ новой  строки –  это  наиболее часто  употребляемый  специаль5 ный  символ. Другие символы, сопоставленные некоторым операциям управления терминалом, включают  в себя  возврат на  одну  позицию (восьмеричное значение 010, выводится как \b),  табуляцию (011, \t) и возврат каретки (015, \r).

Очень важно различать значение, сохраняемое для символа в файле, и то, как он интерпретируется в различных ситуациях. Например, ког да с клавиатуры вводится возврат на одну  позицию (Backspace), если  этот символ в конкретной системе служит для удаления, ядро  интерпретирует его как отказ от предыдущего введенного символа. В итоге и символ возврата, и символ, стоявший перед ним, исчезают, но введе ние возврата на одну позицию отражается на терминале, курсор перемещается на одну позицию назад.

Если же ввести последовательность

(т. е. сначала \, а потом  символ возврата на одну позицию), то ядро  интерпретирует это не как введение специального символа возврата, а как желание поместить символ возврата в поток ввода, поэтому символ \ отбрасывается, а байт 010 помещается в файл. При  отображении символа возврата на терминале курсор перемещается на место символа \.

При  выводе  файла, содержащего символ  возврата, последний не  интерпретируется терминалом, а вызывает перемещение курсора назад.

Если  файл выведен командой od, символ возврата представлен значением  010 или \b , если указан параметр –c.

Это же относится и к табуляции: при  вводе символ табуляции отобра жается на  терминале  и пересылается программе, выполняющей чтение,  при  выводе он отправляется на терминал и там  интерпретируется.  Но  есть  и различие –  ядро  может быть  настроено таким образом, что будет заменять при  выводе символы табуляции соответствующим количеством пробелов. Символ табуляции устанавливает курсор в позициях 9, 17, 25 и т. д. Команда

$ stty -tabs

вызывает замену символов табуляции пробелами при  выводе  на  тер5 минал (stty(1)).

Аналогично обрабатывается и Return. Ядро отображает на терминале нажатие клавиши Return как символ возврата каретки и разделитель строк, а в файл отправляет только символ новой  строки. При  выводе перед символом новой строки добавляется возврат каретки.

Подход, реализованный в системе UNIX  для представления управляющей  информации, не традиционен, в частности в том,  что касается использования символов новой  строки в конце  строк. Вместо  этого  во многих системах существуют «записи», по одной на строку, каждая из которых содержит не только введенные данные, но и подсчитанное количество символов в строке (и никаких разделителей строк). Другие системы  заканчивают  строку символами возврата  каретки и  новой  строки, потому что  именно  такая  последовательность требуется для вывода  на  большинстве терминалов.  (Понятие  «переход  на  другую строку» (linefeed) обозначает то же самое, что и разделитель строк, поэтому  последовательность, упомянутую  выше, часто  называют «CRLF» (carriage return line feed), что удобнее для произношения.)

Система UNIX не делает ни того, ни другого – нет ни записей, ни подсчета  символов, и файл не содержит байты, которые пользователь или его программы не помещали в него. При  выводе на терминал разделитель строк дополняется возвратом каретки, но программам достаточно обрабатывать только символ новой  строки, т. к.  они  знают только о нем.  В большинстве случаев требуется именно такое поведение. При необходимости на основе  такой простой схемы можно построить и более сложную. Обратного, то есть создания простой схемы на базе более сложной, достичь затруднительно.

Поскольку  конец каждой  строки отмечен  символом новой   строки, можно было  бы ожидать, что и файлы должны оканчиваться какимлибо  специальным символом, скажем  \e  (от  англ. end –  конец). Но,  изучая  вывод  команды od,  вы  не  найдете символа конца  файла, он просто  заканчивается.  Вместо использования специального кода  система подписывает конец файла, просто  сообщая, что данных больше

нет.  Ядро хранит сведения о длинах файлов, поэтому программа обнаруживает конец файла, когда обработает его последний байт.

Программа получает данные файла, используя системный вызов (подпрограмму ядра) read. При каждом вызове read возвращает очередную порцию данных – следующую строку текста, вводимого с терминала, к примеру. Кроме  того, она сообщает, сколько байтов файла было получено, так  что, получив от  read  сообщение  «получено ноль  байтов», можно считать, что достигнут конец файла. Если же какие-либо байты еще  остались, read  вернет часть  из  них.  Действительно, нет  смысла вводить специальный символ конца файла, потому что, как было уже  сказано, смысл байта  зависит от  способа  его  интерпретации. Тем  не менее, все  файлы должны где-нибудь кончаться,  а  так  как все  они должны быть  доступны для  чтения  функцией read,  то  возврат нуля представляет собой  независимый от  интерпретации способ  указания конца файла без использования дополнительных символов.

Когда  программа читает данные с терминала, ядро передает ей каждую вводимую строку только после  ввода  символа новой  строки (т. е. при  нажатии Return). Поэтому, пока символ новой  строки не введен, есть  возможность вернуться и исправить замеченную опечатку. Если  же  ошибка обнаружена после  нажатия  клавиши Return, то  исправлять ее поздно, так как строка уже прочитана программой.

С помощью команды cat  можно наблюдать,  как работает такой построчный ввод.  Обычно  эта  команда для  повышения эффективности буферизует вывод  для  повышения производительности, чтобы выполнять запись крупными блоками, но параметр –u позволяет отключить буферизацию записи, и тогда прочитанные строки немедленно отправляются на вывод:

$ cat                                    Вывод с буферизацией

123

456

789 ctld 123 456 789

$ cat  -u                              Вывод без буферизации

123

123

456

456

789

789

ctld

$

При  нажатии клавиши Return cat  получает очередную строку; при отключенной буферизации полученные данные выводятся сразу.

Теперь  попробуем иначе: введем  несколько символов, а вместо  Return

нажмем ctl5d:

$ cat  -u 123ctld123

Символы выводятся сразу  после  нажатия  комбинации ctl5d,  которая означает  «немедленно отправить напечатанные  символы  программе, выполняющей чтение данных с терминала». В отличие от символа новой строки, ctl5d не передается в программу. Теперь, не вводя  ничего больше, нажмем ctl5d дважды:

$ cat  -u 123ctld123ctld$

Оболочка выводит приглашение  на  ввод,  поскольку команда cat, не получив символов, считает, что достигнут конец файла, и завершается. По нажатию ctl5d все, что было введено на терминале, отправляется программе, выполняющей чтение с терминала. Если  ничего не введено, то программа, не получив очередной порции символов, воспримет это как конец файла. Именно поэтому нажатие ctl5d завершает сеанс – оболочка считает, что ввод окончен. Конечно, символ ctl5d обычно  служит для  извещения об окончании файла, но интересно и его более общее назначение.

Упражнение 2.1.  Что  произойдет при  нажатии  ctl5d  в  редакторе ed?

Сравните с командой

$ ed <file

~

Источник: Керниган Б., Пайк Р., UNIX. Программное окружение. – Пер. с англ. – СПб: Символ-Плюс, 2003. – 416 с., ил.

По теме:

  • Комментарии