UNИX, весна 2008, 07 лекция (от 26 марта)
Материал из eSyr's wiki.
Диктофонная запись: http://esyr.org/lections/audio/uneex_2008_summer/uneex_08_03_26.ogg
Зачем нужны хардлинки?
- Если есть программа, которая меняет своё поведение в зависимости от имени (она его увидит в argv[0]). Для чего это нужно --- экономить байты
- Когда имена лежат в разных каталогах, при чём, если такой способ использования, что пользователеь файлом попользовался и удалил
Содержание |
Два маленьких дополнения: софтлинки и ACL
Жёсткие ссылки это хороший инструмент, но у которого есть два крупных недостатка:
- Вы не можете по определению жесткой ссылки создать эту самую жесткую ссылку на файл в другой ФС (т.к. жесткая ссылка влкючает в себя inode, а их нумерация в каждой ФС своя)
- Вы не можете создать жёсткую ссылку на каталог, это запрещено. Почему это решили запретить: предположим, у нас есть директория d1, а в нём d2, ссылающийся на ту же иноду, что и d1. Фактически, для одного объекта есть два имени: d1 и d1/d2. Можете представить себе рекурсивный разбор (точнее, пожалуй, обход --Pavel): d1, потом d2, потом снова d2, и так, пока память не кончится. И поскольку вы никогда не сможете отличить, какое из имён главное, а какое дополнительное, то так делать запрещено.
Для решения этих проблем есть другой объект ФС: символьная ссылка (такие файлы в выводе ls -l обозначаются символом l). Это файл, в котором хранится "настоящее" имя файла. Там хранится некая подстановка: при обращении к этой ссылке из пути выкидывается имя файла-ссылки и подставлется его содержимое: например, если файл-ссылка .../f1 содержит значение d2/f3/, то обращение фактически будет к .../d2/f3/. И, наконец, если значение файла-ссылки начинается на /, то он и будет взят за фактический путь целиком.
Символьные ссылки придуманы для того, чтобы обойти оба ограничения жестких ссылок. Здесь любая программа точно может отличить символьную ссылку, и большинство вменяемых программ (по умолчанию) по ним не ходят.
Про конфиг: вы можете использовать отладочные конфиг-файлы, например, для функции malloc. В trusted системах бывает нужно, чтобы malloc всегда возвращал память чистую, заполненную нулями. Это можно настроить в некотором конфиге и попросить malloc при каждом вызове читать настройки из этого файла. Однако же, действие это состоит из трех операций (открыть файл, прочитать настройки, закрыть файл). Известно, что символьной ссылке в качестве значения ей прописать все что угодно, это необязательно должен быть реально существующий файл. Можно прописать в неё нужную нам строчку, и тогда для чтения её потребуется не три файловых операции, а одна: readlink().
ACL
В UNIX исп. субъект-субъектная модель со множественным субъектом. Все объекты в ФС нумеруются по одному и тому же списку --- множественных субъектов. Субъекты бывают как уникальные --- пользователи, так и множественные, т.е. группы. И все права субъектов вычисляются по простой арифметике. Всё это в общем довольно естественный способ задания прав доступа, тем не менее, существует несколько use case'ов, когда субъект-субъектная модель работает неудобно. Например, если какому-то пользозвателю надо что-то запретить. Это можно в этой модели реализовать: надо созд. спец. группу, перетаскивать всех пользователей туда, кроме провинившегося, и назначить этому файлу эту группу... Есть теоретическое обоснование, почему эта модель неполная: когда для некоторого файла одной группе надо дать права только на запись, другой --- только на чтение. Чтобы только наметить, в какой парадигме она решается: есть не только уникальная идентификация пользователя, но и объекта. Чтобы облегчить/усложнить себе жизнь, можем еще ввести множественные объекты, т.е. группы объектов, и вот эти уникальные и групповые идентификаторы объектов к пользователям отношения не имеют, там своя классификация. И на основе этих 4 таблиц: список пользователей, групп пользователей, объектов, групп объектов, можно изобразить права, кто что с чем может делать. Тогда эта задача вполне легко решается. Это стандартизовано: такой объектный способ доступа стандартизован в POSIX, называется ACL (access control list), и слово list выдаёт нам его отличие: в субъект-субъектной модели вместе с каждым объектом можно хранить очень мало информации --- 9 битов плюс ещё немного, суммарно в районе 60 бит), а в этой модели, что описано сейчас, этой информации может быть столько, что на сами объекты на диске места останется с гулькин нос. Чтобы это обойти, водружаются групповые политики, правила наследования .... с одной стороны, это сильно загромождает понимание того, кто что в итоге может, особенно введение наследования. Не смотря на то,что оно подджерживается большинством Линух-систем, пользоваться ей надо в исключительных случаях. Был случай, когда школьники пришли на олимпиаду, а им всем оказался разрешен доступ на сетевой диск на запись, именно из-за какой-то ошибки в ACL.
Соответствующие команды (если нужный пакет установлен) называются setfacl/getfacl.
Краткий обзор шелла как ЯП
Нынче немодно говорить, что шелл --- полный ЯП, а BAT --- неполный. Говорят, что CMD полный.
Поговорим про то, что такое скрипт --- сценарий с т. з. юних систем. Уже говорилось, что в юних, а в след за ним и в линух свойство файла быть запускаемым опр. специальным режимом доступа (использование). При этом этот файл внутри себя может быть как бинарником, а может быть и текстовым. Для вып. этого файла запускается интерпретатор, который его интерп. По умолчанию этот интерпретатор --- шелл. Именно поэтому, когда говорят скрипт, имеют в виду шеллскрипт. Это искл, которому доверять не надо. В линух принято след. правило: сценарий --- файл, который начинается с #!<интерпретатор>/ "то первая строка файла, например #!/bin/sh. Эта строчка позволяет системе решить,что этот файл должен исполняться соотв. интерпретатором. Запустили prog 1 2 3, а у prog написано #!/bin/sh, то запустится на самом деле /bin/sh prog 1 2 3, причём шелл делает так, что список аргументов начинается с prog. На самом деле, скрипты пишутся на чём угодно: perl, python, ..., лишь бы интерпретатор проигнорировал sha-bang (эту самую первую строчку). Отсюда замечательное свойство --- во многих языках строка с решётки --- комментарий. Ещё одно свойство --- сказав chmod +x, сделал из скрипта программу.
Практически на тех же правах, что и перем. окруж, определяется куча пареметров разных, в том числе для работы ... . Переменная $0 будет соотв. нулевому аргументу, $1 --- первому, и так далее до 9. Ещё есть такая команда shift, которая без параметров производит сдвижку на 1 параметр вправо (2 в 1, 3 в 2, ..., 10 в 9). Зачем это нужно: у вас там флаги, потом имена файлов. Вы флаги прошифтили, а дальше только имена файлов, можно обрабатывать их в цикле. $* --- строка целиком. $@ тоже содержит строку целиком, заведена она для того, чтобы операцию подстановки внутри кавычек. Разница при квотировании: "$*" --- одна большая строка ("$1 $2 $3"), а результатом "$@" будут отдельные параметры ("$1" "$2" "$3"). Если посмотреть на $@ то кажется, что это специфическая, контексно-зависимая штука, потому что работает иначе, но пользоваться этим удобно. Что ещё есть: $# --- количество параметров командной строки.
- $_ --- последняя введённая польз. строка
- $$ --- pid запущенного процесса.
- $! --- pid последнего из процессов, запущенных в фоне
Списки
Списки --- списки команд. Если захотелось, чтобы несколько команд работало вместе, например, чтобы они выводили в один файл. Можно сделать
cmd1 > f cmd2 >> f ...
а можно сделать
{cmd1; cmd2;} > f
Про скобки: можно рассматривать их как операторные скобки. Одно из свойств фигурных скобок состоит в том, что ввод-вывод объединяется. Если для того, чтобы запустить эти команды, не надо запусктаь отдельного шелла, то они выполн. в текущем. Но если нужно, то запускаются отдельно: echo ... | read A, то ... .Если же записать круглые скобки: (cmd1; cmd2) > f, то обязательно запускается отдельный шелл. Этод удобно для того, чтобы понаопределять переменных, а потом всё забыть
Условный оператор
if <список>; then <список>; [else <список>;] fi
Точки в запятыми обязательными, чтобы шелл не посчитал then очередным параметров. Встаёт вопрос, когда выполняется then, в других else. Все мы знаем,что 0 --- ложь, всё остальное --- истина. В типизированных языках есть специальный тип. Шелл заточен под работу с программами, поэтому он использует exit status. Программа по завершении возвращает exit status. Существует ячейка, которую программа по окончанию работы она заполняет всегда. Код завершения последней запущенной программы лежит в $?. На exit status распрост. след правило: если он равен 0, то программа заверш. успешно, иначе рпограмма завершилась ошибкой с кодом exit status. Условная команда в шелл выаолн. список команд, и елси он выполняется успешно, то выполняется then, иначе else. Как опр. код заверш. в списке --- по последней команде. Если код завершения --- 0, то выполняется then, иначе else.
Два амперсенда --- более короткий способ записи условного оператора. Последовательность команд может быть объединена не точками с запятыми, а && или ||. Те, кто программировал в си, знает, что там ленивое вычисление лог. выр. В шелле в a || b b выполняется тогда, кгда a завершилдась неуспешно, в && наоборот.
Пример:
test -r logfile && cat logfile || echo File not found
Цикл
while <список>; do <список>; done
Есть break, continue. У каждой есть необязательный параметр, из скольки циклов выскочить. Более сложно устроен for.
for <переменная> in <строка>; do <список>; done
Пример:
for n in `ls`; do echo $n; done
Тут встречаемся с тем, что разделителем в том числе является и перевод строки
case
case <список> in <шаблон>) список ;; ... esac
На самом деле жутко удобная штука, потому что используются wildcards.
Функции
<имя>() { ... $1 --- первый позиционный параметр функции }
trap
В шелле есть команда trap, которая позволяет перехватывать сигналы, посылаемые процессы. Синтаксис:
trap <функция> сигнал
B тогда обработчик --- не система, а функция. Никаких специфич. парам. там нет. Единственное, среди списка сигналов есть специальное слово EXIT, которое словом не является, а является флагом выхода из скрипта, функция ыполняется после завершения скрипта. Для чего это нужно --- для того, чтобы удалять файлы, созданные mktemp, например. Делается это следующим образом: пишется функция, которая создаёт временный файл и добавляет его в переменную, написать onexit() { trap - EXIt; cleanfile}
ДЗ: привести пример, что можно, или доказать, что нельзя с использованием сигналов сделать очередь для диспетчеризации процессов на разные процессоры...
|
|